You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by GitBox <gi...@apache.org> on 2018/11/01 18:39:58 UTC

[GitHub] ccollins476ad closed pull request #230: target [sysinit | sysdown] commands

ccollins476ad closed pull request #230: target [sysinit | sysdown] commands
URL: https://github.com/apache/mynewt-newt/pull/230
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/newt/builder/targetbuild.go b/newt/builder/targetbuild.go
index e4ccc218..9ee7317d 100644
--- a/newt/builder/targetbuild.go
+++ b/newt/builder/targetbuild.go
@@ -45,8 +45,6 @@ import (
 	"mynewt.apache.org/newt/newt/resolve"
 	"mynewt.apache.org/newt/newt/symbol"
 	"mynewt.apache.org/newt/newt/syscfg"
-	"mynewt.apache.org/newt/newt/sysdown"
-	"mynewt.apache.org/newt/newt/sysinit"
 	"mynewt.apache.org/newt/newt/target"
 	"mynewt.apache.org/newt/newt/toolchain"
 	"mynewt.apache.org/newt/util"
@@ -101,6 +99,9 @@ func NewTargetTester(target *target.Target,
 		injectedSettings: map[string]string{},
 	}
 
+	// Indicate that this version of newt supports the generated logcfg header.
+	t.InjectSetting("NEWT_FEATURE_LOGCFG", "1")
+
 	return t, nil
 }
 
@@ -213,66 +214,59 @@ func (t *TargetBuilder) validateAndWriteCfg() error {
 		log.Warn(line)
 	}
 
-	if err := syscfg.EnsureWritten(t.res.Cfg,
-		GeneratedIncludeDir(t.target.Name())); err != nil {
+	incDir := GeneratedIncludeDir(t.target.Name())
+	srcDir := GeneratedSrcDir(t.target.Name())
 
+	if err := syscfg.EnsureWritten(t.res.Cfg, incDir); err != nil {
 		return err
 	}
 
-	return nil
-}
-
-func (t *TargetBuilder) generateSysinit() error {
-	if err := t.ensureResolved(); err != nil {
+	if err := t.res.LCfg.EnsureWritten(incDir); err != nil {
 		return err
 	}
 
-	srcDir := GeneratedSrcDir(t.target.Name())
-
+	// Generate loader sysinit.
 	if t.res.LoaderSet != nil {
 		lpkgs := resolve.RpkgSliceToLpkgSlice(t.res.LoaderSet.Rpkgs)
-		sysinit.EnsureWritten(lpkgs, srcDir,
-			pkg.ShortName(t.target.Package()), true)
+		if err := t.res.SysinitCfg.EnsureWritten(lpkgs, srcDir,
+			pkg.ShortName(t.target.Package()), true); err != nil {
+
+			return err
+		}
 	}
 
+	// Generate app sysinit.
 	lpkgs := resolve.RpkgSliceToLpkgSlice(t.res.AppSet.Rpkgs)
-	sysinit.EnsureWritten(lpkgs, srcDir,
-		pkg.ShortName(t.target.Package()), false)
+	if err := t.res.SysinitCfg.EnsureWritten(lpkgs, srcDir,
+		pkg.ShortName(t.target.Package()), false); err != nil {
 
-	return nil
-}
-
-func (t *TargetBuilder) generateSysdown() error {
-	if err := t.ensureResolved(); err != nil {
 		return err
 	}
 
-	srcDir := GeneratedSrcDir(t.target.Name())
+	// Generate loader sysinit.
+	if t.res.LoaderSet != nil {
+		lpkgs := resolve.RpkgSliceToLpkgSlice(t.res.LoaderSet.Rpkgs)
+		if err := t.res.SysdownCfg.EnsureWritten(lpkgs, srcDir,
+			pkg.ShortName(t.target.Package()), true); err != nil {
 
-	lpkgs := resolve.RpkgSliceToLpkgSlice(t.res.AppSet.Rpkgs)
-	sysdown.EnsureWritten(lpkgs, t.res.Cfg, srcDir,
-		pkg.ShortName(t.target.Package()))
+			return err
+		}
+	}
 
-	return nil
-}
+	// XXX: Generate loader sysdown.
 
-func (t *TargetBuilder) generateFlashMap() error {
-	return t.bspPkg.FlashMap.EnsureWritten(
-		GeneratedSrcDir(t.target.Name()),
-		GeneratedIncludeDir(t.target.Name()),
-		pkg.ShortName(t.target.Package()))
-}
+	// Generate app sysdown.
+	lpkgs = resolve.RpkgSliceToLpkgSlice(t.res.AppSet.Rpkgs)
+	if err := t.res.SysdownCfg.EnsureWritten(lpkgs, srcDir,
+		pkg.ShortName(t.target.Package()), false); err != nil {
 
-func (t *TargetBuilder) generateCode() error {
-	if err := t.generateSysinit(); err != nil {
 		return err
 	}
 
-	if err := t.generateSysdown(); err != nil {
-		return err
-	}
+	// Generate flash map.
+	if err := t.bspPkg.FlashMap.EnsureWritten(srcDir, incDir,
+		pkg.ShortName(t.target.Package())); err != nil {
 
-	if err := t.generateFlashMap(); err != nil {
 		return err
 	}
 
@@ -330,10 +324,6 @@ func (t *TargetBuilder) PrepBuild() error {
 
 	logDepInfo(t.res)
 
-	if err := t.generateCode(); err != nil {
-		return err
-	}
-
 	return nil
 }
 
diff --git a/newt/cli/target_cfg_cmds.go b/newt/cli/target_cfg_cmds.go
new file mode 100644
index 00000000..69665196
--- /dev/null
+++ b/newt/cli/target_cfg_cmds.go
@@ -0,0 +1,856 @@
+/**
+ * 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.
+ */
+
+// Implements commands that show or modify a target's configuration.
+
+package cli
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"sort"
+	"strings"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/spf13/cobra"
+
+	"mynewt.apache.org/newt/newt/builder"
+	"mynewt.apache.org/newt/newt/logcfg"
+	"mynewt.apache.org/newt/newt/newtutil"
+	"mynewt.apache.org/newt/newt/pkg"
+	"mynewt.apache.org/newt/newt/resolve"
+	"mynewt.apache.org/newt/newt/stage"
+	"mynewt.apache.org/newt/newt/syscfg"
+	"mynewt.apache.org/newt/newt/sysdown"
+	"mynewt.apache.org/newt/newt/sysinit"
+	"mynewt.apache.org/newt/newt/val"
+	"mynewt.apache.org/newt/util"
+)
+
+func printSetting(entry syscfg.CfgEntry) {
+	util.StatusMessage(util.VERBOSITY_DEFAULT,
+		"  * Setting: %s\n", entry.Name)
+
+	util.StatusMessage(util.VERBOSITY_DEFAULT,
+		"    * Description: %s\n", entry.Description)
+
+	util.StatusMessage(util.VERBOSITY_DEFAULT,
+		"    * Value: %s", entry.Value)
+
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+
+	if len(entry.History) > 1 {
+		util.StatusMessage(util.VERBOSITY_DEFAULT,
+			"    * Overridden: ")
+		for i := 1; i < len(entry.History); i++ {
+			util.StatusMessage(util.VERBOSITY_DEFAULT, "%s, ",
+				entry.History[i].Source.FullName())
+		}
+		util.StatusMessage(util.VERBOSITY_DEFAULT,
+			"default=%s\n", entry.History[0].Value)
+	}
+	if len(entry.ValueRefName) > 0 {
+		util.StatusMessage(util.VERBOSITY_DEFAULT,
+			"    * Copied from: %s\n",
+			entry.ValueRefName)
+	}
+}
+
+func printBriefSetting(entry syscfg.CfgEntry) {
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "  %s: %s",
+		entry.Name, entry.Value)
+
+	var extras []string
+
+	if len(entry.History) > 1 {
+		s := fmt.Sprintf("overridden by %s",
+			entry.History[len(entry.History)-1].Source.FullName())
+		extras = append(extras, s)
+	}
+	if len(entry.ValueRefName) > 0 {
+		s := fmt.Sprintf("copied from %s", entry.ValueRefName)
+		extras = append(extras, s)
+	}
+
+	if len(extras) > 0 {
+		util.StatusMessage(util.VERBOSITY_DEFAULT, " (%s)",
+			strings.Join(extras, ", "))
+	}
+
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+}
+
+func printPkgCfg(pkgName string, cfg syscfg.Cfg, entries []syscfg.CfgEntry) {
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "* PACKAGE: %s\n", pkgName)
+
+	settingNames := make([]string, len(entries))
+	for i, entry := range entries {
+		settingNames[i] = entry.Name
+	}
+	sort.Strings(settingNames)
+
+	for _, name := range settingNames {
+		printSetting(cfg.Settings[name])
+	}
+}
+
+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))
+	for pkgName, _ := range pkgNameEntryMap {
+		pkgNames = append(pkgNames, pkgName)
+	}
+	sort.Strings(pkgNames)
+
+	for i, pkgName := range pkgNames {
+		if i > 0 {
+			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+		}
+		printPkgCfg(pkgName, cfg, pkgNameEntryMap[pkgName])
+	}
+}
+
+func printPkgBriefCfg(pkgName string, cfg syscfg.Cfg, entries []syscfg.CfgEntry) {
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "[%s]\n", pkgName)
+
+	settingNames := make([]string, len(entries))
+	for i, entry := range entries {
+		settingNames[i] = entry.Name
+	}
+	sort.Strings(settingNames)
+
+	for _, name := range settingNames {
+		printBriefSetting(cfg.Settings[name])
+	}
+}
+
+func printBriefCfg(targetName string, cfg syscfg.Cfg) {
+	if errText := cfg.ErrorText(); errText != "" {
+		util.StatusMessage(util.VERBOSITY_DEFAULT, "!!! %s\n\n", errText)
+	}
+
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "Brief syscfg for %s:\n", targetName)
+	pkgNameEntryMap := syscfg.EntriesByPkg(cfg)
+
+	pkgNames := make([]string, 0, len(pkgNameEntryMap))
+	for pkgName, _ := range pkgNameEntryMap {
+		pkgNames = append(pkgNames, pkgName)
+	}
+	sort.Strings(pkgNames)
+
+	for i, pkgName := range pkgNames {
+		if i > 0 {
+			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+		}
+		printPkgBriefCfg(pkgName, cfg, pkgNameEntryMap[pkgName])
+	}
+}
+
+func yamlPkgCfg(w io.Writer, pkgName string, cfg syscfg.Cfg,
+	entries []syscfg.CfgEntry) {
+
+	settingNames := make([]string, len(entries))
+	for i, entry := range entries {
+		settingNames[i] = entry.Name
+	}
+	sort.Strings(settingNames)
+
+	fmt.Fprintf(w, "    ### %s\n", pkgName)
+	for _, name := range settingNames {
+		fmt.Fprintf(w, "    %s: '%s'\n", name, cfg.Settings[name].Value)
+	}
+}
+
+func yamlCfg(cfg syscfg.Cfg) string {
+	if errText := cfg.ErrorText(); errText != "" {
+		util.StatusMessage(util.VERBOSITY_DEFAULT, "!!! %s\n\n", errText)
+	}
+
+	pkgNameEntryMap := syscfg.EntriesByPkg(cfg)
+
+	pkgNames := make([]string, 0, len(pkgNameEntryMap))
+	for pkgName, _ := range pkgNameEntryMap {
+		pkgNames = append(pkgNames, pkgName)
+	}
+	sort.Strings(pkgNames)
+
+	buf := bytes.Buffer{}
+
+	fmt.Fprintf(&buf, "syscfg.vals:\n")
+	for i, pkgName := range pkgNames {
+		if i > 0 {
+			fmt.Fprintf(&buf, "\n")
+		}
+		yamlPkgCfg(&buf, pkgName, cfg, pkgNameEntryMap[pkgName])
+	}
+
+	return string(buf.Bytes())
+}
+
+func targetBuilderConfigResolve(b *builder.TargetBuilder) *resolve.Resolution {
+	res, err := b.Resolve()
+	if err != nil {
+		NewtUsage(nil, err)
+	}
+
+	warningText := strings.TrimSpace(res.WarningText())
+	if warningText != "" {
+		log.Warn(warningText + "\n")
+	}
+
+	return res
+}
+
+func targetConfigShowCmd(cmd *cobra.Command, args []string) {
+	if len(args) < 1 {
+		NewtUsage(cmd,
+			util.NewNewtError("Must specify target or unittest name"))
+	}
+
+	TryGetProject()
+
+	for i, arg := range args {
+		b, err := TargetBuilderForTargetOrUnittest(arg)
+		if err != nil {
+			NewtUsage(cmd, err)
+		}
+
+		res := targetBuilderConfigResolve(b)
+		printCfg(b.GetTarget().Name(), res.Cfg)
+
+		if i < len(args)-1 {
+			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+		}
+	}
+}
+
+func targetConfigBriefCmd(cmd *cobra.Command, args []string) {
+	if len(args) < 1 {
+		NewtUsage(cmd,
+			util.NewNewtError("Must specify target or unittest name"))
+	}
+
+	TryGetProject()
+
+	for i, arg := range args {
+		b, err := TargetBuilderForTargetOrUnittest(arg)
+		if err != nil {
+			NewtUsage(cmd, err)
+		}
+
+		res := targetBuilderConfigResolve(b)
+		printBriefCfg(b.GetTarget().Name(), res.Cfg)
+
+		if i < len(args)-1 {
+			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+		}
+	}
+}
+
+func valSettingString(vs val.ValSetting) string {
+	intVal, _ := vs.IntVal()
+
+	s := fmt.Sprintf("%d", intVal)
+	if vs.RefName != "" {
+		s += fmt.Sprintf("%*s [%s]", 16-len(s), "", vs.RefName)
+	}
+
+	return s
+}
+
+func logLevelString(ls val.ValSetting) string {
+	intVal, _ := ls.IntVal()
+
+	s := fmt.Sprintf("%d (%s)", intVal, logcfg.LogLevelString(intVal))
+	if ls.RefName != "" {
+		s += fmt.Sprintf("%*s [%s]", 16-len(s), "", ls.RefName)
+	}
+
+	return s
+}
+
+func printLogCfgOne(l logcfg.Log) {
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "%s:\n", l.Name)
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "    Package: %s\n",
+		l.Source.FullName())
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "    Module:  %s\n",
+		valSettingString(l.Module))
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "    Level:   %s\n",
+		logLevelString(l.Level))
+}
+
+func printLogCfg(targetName string, lcfg logcfg.LCfg) {
+	if errText := lcfg.ErrorText(); errText != "" {
+		util.StatusMessage(util.VERBOSITY_DEFAULT, "!!! %s\n\n", errText)
+	}
+
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "Log config for %s:\n",
+		targetName)
+
+	logNames := make([]string, 0, len(lcfg.Logs))
+	for name, _ := range lcfg.Logs {
+		logNames = append(logNames, name)
+	}
+	sort.Strings(logNames)
+
+	for i, logName := range logNames {
+		if i > 0 {
+			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+		}
+		printLogCfgOne(lcfg.Logs[logName])
+	}
+}
+
+func targetLogShowCmd(cmd *cobra.Command, args []string) {
+	if len(args) < 1 {
+		NewtUsage(cmd,
+			util.NewNewtError("Must specify target or unittest name"))
+	}
+
+	TryGetProject()
+
+	for i, arg := range args {
+		b, err := TargetBuilderForTargetOrUnittest(arg)
+		if err != nil {
+			NewtUsage(cmd, err)
+		}
+
+		res := targetBuilderConfigResolve(b)
+		printLogCfg(b.GetTarget().Name(), res.LCfg)
+
+		if i < len(args)-1 {
+			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+		}
+	}
+}
+
+func printLogCfgBriefOne(l logcfg.Log, colWidth int) {
+	intMod, _ := l.Module.IntVal()
+	intLevel, _ := l.Level.IntVal()
+
+	levelStr := fmt.Sprintf("%d (%s)", intLevel,
+		logcfg.LogLevelString(intLevel))
+
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "%*s | %-8d | %-12s\n",
+		colWidth, l.Name, intMod, levelStr)
+}
+
+func printLogCfgBrief(targetName string, lcfg logcfg.LCfg) {
+	if errText := lcfg.ErrorText(); errText != "" {
+		util.StatusMessage(util.VERBOSITY_DEFAULT, "!!! %s\n\n", errText)
+	}
+
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "Brief log config for %s:\n",
+		targetName)
+
+	longest := 6
+	logNames := make([]string, 0, len(lcfg.Logs))
+	for name, _ := range lcfg.Logs {
+		logNames = append(logNames, name)
+		if len(name) > longest {
+			longest = len(name)
+		}
+	}
+	sort.Strings(logNames)
+
+	colWidth := longest + 4
+	util.StatusMessage(util.VERBOSITY_DEFAULT,
+		"%*s | MODULE   | LEVEL\n", colWidth, "LOG")
+	util.StatusMessage(util.VERBOSITY_DEFAULT,
+		"%s-+----------+--------------\n",
+		strings.Repeat("-", colWidth))
+	for _, logName := range logNames {
+		printLogCfgBriefOne(lcfg.Logs[logName], colWidth)
+	}
+}
+
+func targetLogBriefCmd(cmd *cobra.Command, args []string) {
+	if len(args) < 1 {
+		NewtUsage(cmd,
+			util.NewNewtError("Must specify target or unittest name"))
+	}
+
+	TryGetProject()
+
+	for i, arg := range args {
+		b, err := TargetBuilderForTargetOrUnittest(arg)
+		if err != nil {
+			NewtUsage(cmd, err)
+		}
+
+		res := targetBuilderConfigResolve(b)
+		printLogCfgBrief(b.GetTarget().Name(), res.LCfg)
+
+		if i < len(args)-1 {
+			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+		}
+	}
+}
+
+func printStage(sf stage.StageFunc) {
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "%s:\n", sf.Name)
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "    Package: %s\n",
+		sf.Pkg.FullName())
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "    Stage:  %s\n",
+		valSettingString(sf.Stage))
+}
+
+func printStageBriefOne(sf stage.StageFunc,
+	stageWidth int, pkgWidth int, fnWidth int, settingWidth int) {
+
+	util.StatusMessage(util.VERBOSITY_DEFAULT, " %-*s | %-*s | %-*s | %-*s\n",
+		stageWidth, sf.Stage.Value,
+		pkgWidth, sf.Pkg.FullName(),
+		fnWidth, sf.Name,
+		settingWidth, sf.Stage.RefName)
+}
+
+func printStageBriefTable(sfs []stage.StageFunc) {
+	longestStage := 5
+	longestPkg := 7
+	longestFn := 8
+	longestSetting := 7
+	for _, sf := range sfs {
+		if len(sf.Stage.Value) > longestStage {
+			longestStage = len(sf.Stage.Value)
+		}
+		if len(sf.Pkg.FullName()) > longestPkg {
+			longestPkg = len(sf.Pkg.FullName())
+		}
+		if len(sf.Name) > longestFn {
+			longestFn = len(sf.Name)
+		}
+		if len(sf.Stage.RefName) > longestSetting {
+			longestSetting = len(sf.Stage.RefName)
+		}
+	}
+
+	stageWidth := longestStage + 2
+	pkgWidth := longestPkg + 2
+	fnWidth := longestFn + 2
+	settingWidth := longestSetting + 2
+
+	util.StatusMessage(util.VERBOSITY_DEFAULT,
+		" %-*s | %-*s | %-*s | %-*s\n",
+		stageWidth, "STAGE",
+		pkgWidth, "PACKAGE",
+		fnWidth, "FUNCTION",
+		settingWidth, "SETTING")
+	util.StatusMessage(util.VERBOSITY_DEFAULT,
+		"-%s-+-%s-+-%s-+-%s-\n",
+		strings.Repeat("-", stageWidth),
+		strings.Repeat("-", pkgWidth),
+		strings.Repeat("-", fnWidth),
+		strings.Repeat("-", settingWidth))
+	for _, sf := range sfs {
+		printStageBriefOne(sf, stageWidth, pkgWidth, fnWidth, settingWidth)
+	}
+}
+
+func printSysinitCfg(targetName string, scfg sysinit.SysinitCfg) {
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "Sysinit config for %s:\n",
+		targetName)
+
+	if errText := scfg.ErrorText(); errText != "" {
+		util.StatusMessage(util.VERBOSITY_DEFAULT, "!!! %s\n\n", errText)
+	}
+
+	for i, sf := range scfg.StageFuncs {
+		if i > 0 {
+			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+		}
+		printStage(sf)
+	}
+}
+
+func printSysinitBrief(targetName string, scfg sysinit.SysinitCfg) {
+	if errText := scfg.ErrorText(); errText != "" {
+		util.StatusMessage(util.VERBOSITY_DEFAULT, "!!! %s\n\n", errText)
+	}
+
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "Brief sysinit config for %s:\n",
+		targetName)
+
+	printStageBriefTable(scfg.StageFuncs)
+}
+
+func targetSysinitShowCmd(cmd *cobra.Command, args []string) {
+	if len(args) < 1 {
+		NewtUsage(cmd,
+			util.NewNewtError("Must specify target or unittest name"))
+	}
+
+	TryGetProject()
+
+	for i, arg := range args {
+		b, err := TargetBuilderForTargetOrUnittest(arg)
+		if err != nil {
+			NewtUsage(cmd, err)
+		}
+
+		res := targetBuilderConfigResolve(b)
+		printSysinitCfg(b.GetTarget().Name(), res.SysinitCfg)
+
+		if i < len(args)-1 {
+			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+		}
+	}
+}
+
+func targetSysinitBriefCmd(cmd *cobra.Command, args []string) {
+	if len(args) < 1 {
+		NewtUsage(cmd,
+			util.NewNewtError("Must specify target or unittest name"))
+	}
+
+	TryGetProject()
+
+	for i, arg := range args {
+		b, err := TargetBuilderForTargetOrUnittest(arg)
+		if err != nil {
+			NewtUsage(cmd, err)
+		}
+
+		res := targetBuilderConfigResolve(b)
+		printSysinitBrief(b.GetTarget().Name(), res.SysinitCfg)
+
+		if i < len(args)-1 {
+			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+		}
+	}
+}
+
+func printSysdownCfg(targetName string, scfg sysdown.SysdownCfg) {
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "Sysdown config for %s:\n",
+		targetName)
+
+	if errText := scfg.ErrorText(); errText != "" {
+		util.StatusMessage(util.VERBOSITY_DEFAULT, "!!! %s\n\n", errText)
+	}
+
+	for i, sf := range scfg.StageFuncs {
+		if i > 0 {
+			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+		}
+		printStage(sf)
+	}
+}
+
+func targetSysdownShowCmd(cmd *cobra.Command, args []string) {
+	if len(args) < 1 {
+		NewtUsage(cmd,
+			util.NewNewtError("Must specify target or unittest name"))
+	}
+
+	TryGetProject()
+
+	for i, arg := range args {
+		b, err := TargetBuilderForTargetOrUnittest(arg)
+		if err != nil {
+			NewtUsage(cmd, err)
+		}
+
+		res := targetBuilderConfigResolve(b)
+		printSysdownCfg(b.GetTarget().Name(), res.SysdownCfg)
+
+		if i < len(args)-1 {
+			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+		}
+	}
+}
+
+func printSysdownBrief(targetName string, scfg sysdown.SysdownCfg) {
+	if errText := scfg.ErrorText(); errText != "" {
+		util.StatusMessage(util.VERBOSITY_DEFAULT, "!!! %s\n\n", errText)
+	}
+
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "Brief sysdown config for %s:\n",
+		targetName)
+
+	printStageBriefTable(scfg.StageFuncs)
+}
+
+func targetSysdownBriefCmd(cmd *cobra.Command, args []string) {
+	if len(args) < 1 {
+		NewtUsage(cmd,
+			util.NewNewtError("Must specify target or unittest name"))
+	}
+
+	TryGetProject()
+
+	for i, arg := range args {
+		b, err := TargetBuilderForTargetOrUnittest(arg)
+		if err != nil {
+			NewtUsage(cmd, err)
+		}
+
+		res := targetBuilderConfigResolve(b)
+		printSysdownBrief(b.GetTarget().Name(), res.SysdownCfg)
+
+		if i < len(args)-1 {
+			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+		}
+	}
+}
+
+func targetConfigInitCmd(cmd *cobra.Command, args []string) {
+	if len(args) < 1 {
+		NewtUsage(cmd,
+			util.NewNewtError("Must specify target or unittest name"))
+	}
+
+	type entry struct {
+		lpkg   *pkg.LocalPackage
+		path   string
+		b      *builder.TargetBuilder
+		exists bool
+	}
+
+	TryGetProject()
+
+	anyExist := false
+	entries := make([]entry, len(args))
+	for i, pkgName := range args {
+		e := &entries[i]
+
+		b, err := TargetBuilderForTargetOrUnittest(pkgName)
+		if err != nil {
+			NewtUsage(cmd, err)
+		}
+		e.b = b
+
+		e.lpkg = b.GetTestPkg()
+		if e.lpkg == nil {
+			e.lpkg = b.GetTarget().Package()
+		}
+
+		e.path = builder.PkgSyscfgPath(e.lpkg.BasePath())
+
+		if util.NodeExist(e.path) {
+			e.exists = true
+			anyExist = true
+		}
+	}
+
+	if anyExist && !newtutil.NewtForce {
+		util.StatusMessage(util.VERBOSITY_DEFAULT,
+			"Configuration files already exist:\n")
+		for _, e := range entries {
+			if e.exists {
+				util.StatusMessage(util.VERBOSITY_DEFAULT, "    * %s\n",
+					e.path)
+			}
+		}
+		util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
+
+		fmt.Printf("Overwrite them? (y/N): ")
+		rsp := PromptYesNo(false)
+		if !rsp {
+			return
+		}
+	}
+
+	for _, e := range entries {
+		res := targetBuilderConfigResolve(e.b)
+		yaml := yamlCfg(res.Cfg)
+
+		if err := ioutil.WriteFile(e.path, []byte(yaml), 0644); err != nil {
+			NewtUsage(nil, util.FmtNewtError("Error writing file \"%s\"; %s",
+				e.path, err.Error()))
+		}
+	}
+}
+
+func targetCfgCmdAll() []*cobra.Command {
+	cmds := []*cobra.Command{}
+
+	configHelpText := "View or populate a target's system configuration"
+
+	configCmd := &cobra.Command{
+		Use:   "config",
+		Short: configHelpText,
+		Long:  configHelpText,
+		Run: func(cmd *cobra.Command, args []string) {
+			cmd.Usage()
+		},
+	}
+
+	cmds = append(cmds, configCmd)
+
+	configShowCmd := &cobra.Command{
+		Use:   "show <target> [target...]",
+		Short: "View a target's system configuration",
+		Long:  "View a target's system configuration",
+		Run:   targetConfigShowCmd,
+	}
+
+	configCmd.AddCommand(configShowCmd)
+	AddTabCompleteFn(configShowCmd, func() []string {
+		return append(targetList(), unittestList()...)
+	})
+
+	configBriefCmd := &cobra.Command{
+		Use:   "brief <target> [target...]",
+		Short: "View a summary of target's system configuration",
+		Long:  "View a summary of target's system configuration",
+		Run:   targetConfigBriefCmd,
+	}
+
+	configCmd.AddCommand(configBriefCmd)
+	AddTabCompleteFn(configBriefCmd, func() []string {
+		return append(targetList(), unittestList()...)
+	})
+
+	configInitCmd := &cobra.Command{
+		Use:   "init",
+		Short: "Populate a target's system configuration file",
+		Long: "Populate a target's system configuration file (syscfg). " +
+			"Unspecified settings are given default values.",
+		Run: targetConfigInitCmd,
+	}
+	configInitCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
+		"force", "f", false,
+		"Force overwrite of target configuration")
+
+	configCmd.AddCommand(configInitCmd)
+	AddTabCompleteFn(configInitCmd, func() []string {
+		return append(targetList(), unittestList()...)
+	})
+
+	logHelpText := "View a target's log configuration"
+
+	logCmd := &cobra.Command{
+		Use:   "logcfg",
+		Short: logHelpText,
+		Long:  logHelpText,
+		Run: func(cmd *cobra.Command, args []string) {
+			cmd.Usage()
+		},
+	}
+
+	cmds = append(cmds, logCmd)
+
+	logShowCmd := &cobra.Command{
+		Use:   "show <target> [target...]",
+		Short: "View a target's log configuration",
+		Long:  "View a target's log configuration",
+		Run:   targetLogShowCmd,
+	}
+
+	logCmd.AddCommand(logShowCmd)
+	AddTabCompleteFn(logShowCmd, func() []string {
+		return append(targetList(), unittestList()...)
+	})
+
+	logBriefCmd := &cobra.Command{
+		Use:   "brief <target> [target...]",
+		Short: "View a summary of target's log configuration",
+		Long:  "View a summary of target's log configuration",
+		Run:   targetLogBriefCmd,
+	}
+
+	logCmd.AddCommand(logBriefCmd)
+	AddTabCompleteFn(logBriefCmd, func() []string {
+		return append(targetList(), unittestList()...)
+	})
+
+	sysinitHelpText := "View a target's sysinit configuration"
+
+	sysinitCmd := &cobra.Command{
+		Use:   "sysinit",
+		Short: sysinitHelpText,
+		Long:  sysinitHelpText,
+		Run: func(cmd *cobra.Command, args []string) {
+			cmd.Usage()
+		},
+	}
+
+	cmds = append(cmds, sysinitCmd)
+
+	sysinitShowCmd := &cobra.Command{
+		Use:   "show <target> [target...]",
+		Short: "View a target's sysinit configuration",
+		Long:  "View a target's sysinit configuration",
+		Run:   targetSysinitShowCmd,
+	}
+
+	sysinitCmd.AddCommand(sysinitShowCmd)
+	AddTabCompleteFn(sysinitShowCmd, func() []string {
+		return append(targetList(), unittestList()...)
+	})
+
+	sysinitBriefCmd := &cobra.Command{
+		Use:   "brief <target> [target...]",
+		Short: "View a summary of target's sysinit configuration",
+		Long:  "View a summary of target's sysinit configuration",
+		Run:   targetSysinitBriefCmd,
+	}
+
+	sysinitCmd.AddCommand(sysinitBriefCmd)
+	AddTabCompleteFn(sysinitBriefCmd, func() []string {
+		return append(targetList(), unittestList()...)
+	})
+
+	sysdownHelpText := "View a target's sysdown configuration"
+
+	sysdownCmd := &cobra.Command{
+		Use:   "sysdown",
+		Short: sysdownHelpText,
+		Long:  sysdownHelpText,
+		Run: func(cmd *cobra.Command, args []string) {
+			cmd.Usage()
+		},
+	}
+
+	cmds = append(cmds, sysdownCmd)
+
+	sysdownShowCmd := &cobra.Command{
+		Use:   "show <target> [target...]",
+		Short: "View a target's sysdown configuration",
+		Long:  "View a target's sysdown configuration",
+		Run:   targetSysdownShowCmd,
+	}
+
+	sysdownCmd.AddCommand(sysdownShowCmd)
+	AddTabCompleteFn(sysdownShowCmd, func() []string {
+		return append(targetList(), unittestList()...)
+	})
+
+	sysdownBriefCmd := &cobra.Command{
+		Use:   "brief <target> [target...]",
+		Short: "View a summary of target's sysdown configuration",
+		Long:  "View a summary of target's sysdown configuration",
+		Run:   targetSysdownBriefCmd,
+	}
+
+	sysdownCmd.AddCommand(sysdownBriefCmd)
+	AddTabCompleteFn(sysdownBriefCmd, func() []string {
+		return append(targetList(), unittestList()...)
+	})
+
+	return cmds
+}
diff --git a/newt/cli/target_cmds.go b/newt/cli/target_cmds.go
index bf7d6ddf..04c32603 100644
--- a/newt/cli/target_cmds.go
+++ b/newt/cli/target_cmds.go
@@ -22,14 +22,13 @@ package cli
 import (
 	"bytes"
 	"fmt"
-	"io"
 	"io/ioutil"
 	"os"
 	"sort"
 	"strings"
 
-	log "github.com/Sirupsen/logrus"
 	"github.com/spf13/cobra"
+
 	"mynewt.apache.org/newt/newt/builder"
 	"mynewt.apache.org/newt/newt/newtutil"
 	"mynewt.apache.org/newt/newt/pkg"
@@ -552,300 +551,6 @@ func targetCopyCmd(cmd *cobra.Command, args []string) {
 		srcTarget.FullName(), dstTarget.FullName())
 }
 
-func printSetting(entry syscfg.CfgEntry) {
-	util.StatusMessage(util.VERBOSITY_DEFAULT,
-		"  * Setting: %s\n", entry.Name)
-
-	util.StatusMessage(util.VERBOSITY_DEFAULT,
-		"    * Description: %s\n", entry.Description)
-
-	util.StatusMessage(util.VERBOSITY_DEFAULT,
-		"    * Value: %s", entry.Value)
-
-	util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
-
-	if len(entry.History) > 1 {
-		util.StatusMessage(util.VERBOSITY_DEFAULT,
-			"    * Overridden: ")
-		for i := 1; i < len(entry.History); i++ {
-			util.StatusMessage(util.VERBOSITY_DEFAULT, "%s, ",
-				entry.History[i].Source.FullName())
-		}
-		util.StatusMessage(util.VERBOSITY_DEFAULT,
-			"default=%s\n", entry.History[0].Value)
-	}
-	if len(entry.ValueRefName) > 0 {
-		util.StatusMessage(util.VERBOSITY_DEFAULT,
-			"    * Copied from: %s\n",
-			entry.ValueRefName)
-	}
-}
-
-func printBriefSetting(entry syscfg.CfgEntry) {
-	util.StatusMessage(util.VERBOSITY_DEFAULT, "  %s: %s",
-		entry.Name, entry.Value)
-
-	var extras []string
-
-	if len(entry.History) > 1 {
-		s := fmt.Sprintf("overridden by %s",
-			entry.History[len(entry.History)-1].Source.FullName())
-		extras = append(extras, s)
-	}
-	if len(entry.ValueRefName) > 0 {
-		s := fmt.Sprintf("copied from %s", entry.ValueRefName)
-		extras = append(extras, s)
-	}
-
-	if len(extras) > 0 {
-		util.StatusMessage(util.VERBOSITY_DEFAULT, " (%s)",
-			strings.Join(extras, ", "))
-	}
-
-	util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
-}
-
-func printPkgCfg(pkgName string, cfg syscfg.Cfg, entries []syscfg.CfgEntry) {
-	util.StatusMessage(util.VERBOSITY_DEFAULT, "* PACKAGE: %s\n", pkgName)
-
-	settingNames := make([]string, len(entries))
-	for i, entry := range entries {
-		settingNames[i] = entry.Name
-	}
-	sort.Strings(settingNames)
-
-	for _, name := range settingNames {
-		printSetting(cfg.Settings[name])
-	}
-}
-
-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))
-	for pkgName, _ := range pkgNameEntryMap {
-		pkgNames = append(pkgNames, pkgName)
-	}
-	sort.Strings(pkgNames)
-
-	for i, pkgName := range pkgNames {
-		if i > 0 {
-			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
-		}
-		printPkgCfg(pkgName, cfg, pkgNameEntryMap[pkgName])
-	}
-}
-
-func printPkgBriefCfg(pkgName string, cfg syscfg.Cfg, entries []syscfg.CfgEntry) {
-	util.StatusMessage(util.VERBOSITY_DEFAULT, "[%s]\n", pkgName)
-
-	settingNames := make([]string, len(entries))
-	for i, entry := range entries {
-		settingNames[i] = entry.Name
-	}
-	sort.Strings(settingNames)
-
-	for _, name := range settingNames {
-		printBriefSetting(cfg.Settings[name])
-	}
-}
-
-func printBriefCfg(targetName string, cfg syscfg.Cfg) {
-	if errText := cfg.ErrorText(); errText != "" {
-		util.StatusMessage(util.VERBOSITY_DEFAULT, "!!! %s\n\n", errText)
-	}
-
-	util.StatusMessage(util.VERBOSITY_DEFAULT, "Brief syscfg for %s:\n", targetName)
-	pkgNameEntryMap := syscfg.EntriesByPkg(cfg)
-
-	pkgNames := make([]string, 0, len(pkgNameEntryMap))
-	for pkgName, _ := range pkgNameEntryMap {
-		pkgNames = append(pkgNames, pkgName)
-	}
-	sort.Strings(pkgNames)
-
-	for i, pkgName := range pkgNames {
-		if i > 0 {
-			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
-		}
-		printPkgBriefCfg(pkgName, cfg, pkgNameEntryMap[pkgName])
-	}
-}
-
-func yamlPkgCfg(w io.Writer, pkgName string, cfg syscfg.Cfg,
-	entries []syscfg.CfgEntry) {
-
-	settingNames := make([]string, len(entries))
-	for i, entry := range entries {
-		settingNames[i] = entry.Name
-	}
-	sort.Strings(settingNames)
-
-	fmt.Fprintf(w, "    ### %s\n", pkgName)
-	for _, name := range settingNames {
-		fmt.Fprintf(w, "    %s: '%s'\n", name, cfg.Settings[name].Value)
-	}
-}
-
-func yamlCfg(cfg syscfg.Cfg) string {
-	if errText := cfg.ErrorText(); errText != "" {
-		util.StatusMessage(util.VERBOSITY_DEFAULT, "!!! %s\n\n", errText)
-	}
-
-	pkgNameEntryMap := syscfg.EntriesByPkg(cfg)
-
-	pkgNames := make([]string, 0, len(pkgNameEntryMap))
-	for pkgName, _ := range pkgNameEntryMap {
-		pkgNames = append(pkgNames, pkgName)
-	}
-	sort.Strings(pkgNames)
-
-	buf := bytes.Buffer{}
-
-	fmt.Fprintf(&buf, "syscfg.vals:\n")
-	for i, pkgName := range pkgNames {
-		if i > 0 {
-			fmt.Fprintf(&buf, "\n")
-		}
-		yamlPkgCfg(&buf, pkgName, cfg, pkgNameEntryMap[pkgName])
-	}
-
-	return string(buf.Bytes())
-}
-
-func targetBuilderConfigResolve(b *builder.TargetBuilder) *resolve.Resolution {
-	res, err := b.Resolve()
-	if err != nil {
-		NewtUsage(nil, err)
-	}
-
-	warningText := strings.TrimSpace(res.WarningText())
-	if warningText != "" {
-		log.Warn(warningText + "\n")
-	}
-
-	return res
-}
-
-func targetConfigShowCmd(cmd *cobra.Command, args []string) {
-	if len(args) < 1 {
-		NewtUsage(cmd,
-			util.NewNewtError("Must specify target or unittest name"))
-	}
-
-	TryGetProject()
-
-	for i, arg := range args {
-		b, err := TargetBuilderForTargetOrUnittest(arg)
-		if err != nil {
-			NewtUsage(cmd, err)
-		}
-
-		res := targetBuilderConfigResolve(b)
-		printCfg(b.GetTarget().Name(), res.Cfg)
-
-		if i < len(args)-1 {
-			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
-		}
-	}
-}
-
-func targetConfigBriefCmd(cmd *cobra.Command, args []string) {
-	if len(args) < 1 {
-		NewtUsage(cmd,
-			util.NewNewtError("Must specify target or unittest name"))
-	}
-
-	TryGetProject()
-
-	for i, arg := range args {
-		b, err := TargetBuilderForTargetOrUnittest(arg)
-		if err != nil {
-			NewtUsage(cmd, err)
-		}
-
-		res := targetBuilderConfigResolve(b)
-		printBriefCfg(b.GetTarget().Name(), res.Cfg)
-
-		if i < len(args)-1 {
-			util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
-		}
-	}
-}
-
-func targetConfigInitCmd(cmd *cobra.Command, args []string) {
-	if len(args) < 1 {
-		NewtUsage(cmd,
-			util.NewNewtError("Must specify target or unittest name"))
-	}
-
-	type entry struct {
-		lpkg   *pkg.LocalPackage
-		path   string
-		b      *builder.TargetBuilder
-		exists bool
-	}
-
-	TryGetProject()
-
-	anyExist := false
-	entries := make([]entry, len(args))
-	for i, pkgName := range args {
-		e := &entries[i]
-
-		b, err := TargetBuilderForTargetOrUnittest(pkgName)
-		if err != nil {
-			NewtUsage(cmd, err)
-		}
-		e.b = b
-
-		e.lpkg = b.GetTestPkg()
-		if e.lpkg == nil {
-			e.lpkg = b.GetTarget().Package()
-		}
-
-		e.path = builder.PkgSyscfgPath(e.lpkg.BasePath())
-
-		if util.NodeExist(e.path) {
-			e.exists = true
-			anyExist = true
-		}
-	}
-
-	if anyExist && !newtutil.NewtForce {
-		util.StatusMessage(util.VERBOSITY_DEFAULT,
-			"Configuration files already exist:\n")
-		for _, e := range entries {
-			if e.exists {
-				util.StatusMessage(util.VERBOSITY_DEFAULT, "    * %s\n",
-					e.path)
-			}
-		}
-		util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
-
-		fmt.Printf("Overwrite them? (y/N): ")
-		rsp := PromptYesNo(false)
-		if !rsp {
-			return
-		}
-	}
-
-	for _, e := range entries {
-		res := targetBuilderConfigResolve(e.b)
-		yaml := yamlCfg(res.Cfg)
-
-		if err := ioutil.WriteFile(e.path, []byte(yaml), 0644); err != nil {
-			NewtUsage(nil, util.FmtNewtError("Error writing file \"%s\"; %s",
-				e.path, err.Error()))
-		}
-	}
-}
-
 func targetDepCmd(cmd *cobra.Command, args []string) {
 	if len(args) < 1 {
 		NewtUsage(cmd,
@@ -1077,59 +782,6 @@ func AddTargetCommands(cmd *cobra.Command) {
 	targetCmd.AddCommand(copyCmd)
 	AddTabCompleteFn(copyCmd, targetList)
 
-	configHelpText := "View or populate a target's system configuration"
-
-	configCmd := &cobra.Command{
-		Use:   "config",
-		Short: configHelpText,
-		Long:  configHelpText,
-		Run: func(cmd *cobra.Command, args []string) {
-			cmd.Usage()
-		},
-	}
-
-	targetCmd.AddCommand(configCmd)
-
-	configShowCmd := &cobra.Command{
-		Use:   "show <target> [target...]",
-		Short: "View a target's system configuration",
-		Long:  "View a target's system configuration",
-		Run:   targetConfigShowCmd,
-	}
-
-	configCmd.AddCommand(configShowCmd)
-	AddTabCompleteFn(configShowCmd, func() []string {
-		return append(targetList(), unittestList()...)
-	})
-
-	configBriefCmd := &cobra.Command{
-		Use:   "brief <target> [target...]",
-		Short: "View a summary of target's system configuration",
-		Long:  "View a summary of target's system configuration",
-		Run:   targetConfigBriefCmd,
-	}
-
-	configCmd.AddCommand(configBriefCmd)
-	AddTabCompleteFn(configBriefCmd, func() []string {
-		return append(targetList(), unittestList()...)
-	})
-
-	configInitCmd := &cobra.Command{
-		Use:   "init",
-		Short: "Populate a target's system configuration file",
-		Long: "Populate a target's system configuration file (syscfg). " +
-			"Unspecified settings are given default values.",
-		Run: targetConfigInitCmd,
-	}
-	configInitCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
-		"force", "f", false,
-		"Force overwrite of target configuration")
-
-	configCmd.AddCommand(configInitCmd)
-	AddTabCompleteFn(configInitCmd, func() []string {
-		return append(targetList(), unittestList()...)
-	})
-
 	depHelpText := "View a target's dependency graph."
 
 	depCmd := &cobra.Command{
@@ -1157,4 +809,8 @@ func AddTargetCommands(cmd *cobra.Command) {
 	AddTabCompleteFn(revdepCmd, func() []string {
 		return append(targetList(), unittestList()...)
 	})
+
+	for _, cmd := range targetCfgCmdAll() {
+		targetCmd.AddCommand(cmd)
+	}
 }
diff --git a/newt/logcfg/logcfg.go b/newt/logcfg/logcfg.go
new file mode 100644
index 00000000..6b2d66b9
--- /dev/null
+++ b/newt/logcfg/logcfg.go
@@ -0,0 +1,327 @@
+/**
+ * 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 logcfg
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/spf13/cast"
+
+	"mynewt.apache.org/newt/newt/newtutil"
+	"mynewt.apache.org/newt/newt/pkg"
+	"mynewt.apache.org/newt/newt/syscfg"
+	"mynewt.apache.org/newt/newt/val"
+	"mynewt.apache.org/newt/util"
+)
+
+const HEADER_PATH = "logcfg/logcfg.h"
+
+type Log struct {
+	// Log name; equal to the name of the YAML map that defines the log.
+	Name string
+
+	// The package that defines the log.
+	Source *pkg.LocalPackage
+
+	// The log's numeric module ID.
+	Module val.ValSetting
+
+	// The level assigned to this log.
+	Level val.ValSetting
+}
+
+// Map of: [log-name] => log
+type LogMap map[string]Log
+
+// The log configuration of the target.
+type LCfg struct {
+	// [log-name] => log
+	Logs LogMap
+
+	// Strings describing errors encountered while parsing the log config.
+	InvalidSettings []string
+
+	// Contains sets of logs with conflicting module IDs.
+	//     [module-ID] => <slice-of-logs-with-module-id>
+	ModuleConflicts map[int][]Log
+}
+
+// Maps numeric log levels to their string representations.  Used when
+// generating the C log macros.
+var logLevelNames = []string{
+	0: "DEBUG",
+	1: "INFO",
+	2: "WARN",
+	3: "ERROR",
+	4: "CRITICAL",
+}
+
+func LogLevelString(level int) string {
+	if level < 0 || level >= len(logLevelNames) {
+		return "???"
+	}
+
+	return logLevelNames[level]
+}
+
+func NewLCfg() LCfg {
+	return LCfg{
+		Logs:            map[string]Log{},
+		ModuleConflicts: map[int][]Log{},
+	}
+}
+
+// Parses a single log definition from a YAML map.  The `logMapItf` parameter
+// should be a map with the following elements:
+//     "module": <module-string>
+//     "level": <level-string>
+func parseOneLog(name string, lpkg *pkg.LocalPackage, logMapItf interface{},
+	cfg *syscfg.Cfg) (Log, error) {
+
+	cl := Log{
+		Name:   name,
+		Source: lpkg,
+	}
+
+	logMap := cast.ToStringMapString(logMapItf)
+	if logMap == nil {
+		return cl, util.FmtNewtError(
+			"\"%s\" missing required field \"module\"", name)
+	}
+
+	modStr := logMap["module"]
+	if modStr == "" {
+		return cl, util.FmtNewtError(
+			"\"%s\" missing required field \"module\"", name)
+	}
+	mod, err := val.ResolveValSetting(modStr, cfg)
+	if err != nil {
+		return cl, util.FmtNewtError(
+			"\"%s\" contains invalid \"module\": %s",
+			name, err.Error())
+	}
+	if _, err := mod.IntVal(); err != nil {
+		return cl, util.FmtNewtError(
+			"\"%s\" contains invalid \"module\": %s", name, err.Error())
+	}
+
+	levelStr := logMap["level"]
+	if levelStr == "" {
+		return cl, util.FmtNewtError(
+			"\"%s\" missing required field \"level\"", name)
+	}
+	level, err := val.ResolveValSetting(levelStr, cfg)
+	if err != nil {
+		return cl, util.FmtNewtError(
+			"\"%s\" contains invalid \"level\": %s",
+			name, err.Error())
+	}
+	if _, err := level.IntVal(); err != nil {
+		return cl, util.FmtNewtError(
+			"\"%s\" contains invalid \"level\": %s", name, err.Error())
+	}
+
+	cl.Module = mod
+	cl.Level = level
+
+	return cl, nil
+}
+
+// Reads all the logs defined by the specified package.  The log definitions
+// are read from the `syscfg.logs` map in the package's `syscfg.yml` file.
+func (lcfg *LCfg) readOnePkg(lpkg *pkg.LocalPackage, cfg *syscfg.Cfg) {
+	lsettings := cfg.AllSettingsForLpkg(lpkg)
+	logMaps := lpkg.SyscfgY.GetValStringMap("syscfg.logs", lsettings)
+	for name, logMapItf := range logMaps {
+		cl, err := parseOneLog(name, lpkg, logMapItf, cfg)
+		if err != nil {
+			lcfg.InvalidSettings =
+				append(lcfg.InvalidSettings, strings.TrimSpace(err.Error()))
+		} else {
+			lcfg.Logs[cl.Name] = cl
+		}
+	}
+}
+
+// Searches the log configuration for logs with identical module IDs.  The log
+// configuration object is populated with the results.
+func (lcfg *LCfg) detectModuleConflicts() {
+	m := map[int][]Log{}
+
+	for _, l := range lcfg.Logs {
+		intMod, _ := l.Module.IntVal()
+		m[intMod] = append(m[intMod], l)
+	}
+
+	for mod, logs := range m {
+		if len(logs) > 1 {
+			for _, l := range logs {
+				lcfg.ModuleConflicts[mod] =
+					append(lcfg.ModuleConflicts[mod], l)
+			}
+		}
+	}
+}
+
+// Reads all log definitions for each of the specified packages.  The
+// returned LCfg object is populated with the result of this operation.
+func Read(lpkgs []*pkg.LocalPackage, cfg *syscfg.Cfg) LCfg {
+	lcfg := NewLCfg()
+
+	for _, lpkg := range lpkgs {
+		lcfg.readOnePkg(lpkg, cfg)
+	}
+
+	lcfg.detectModuleConflicts()
+
+	return lcfg
+}
+
+// If any errors were encountered while parsing log definitions, this function
+// returns a string indicating the errors.  If no errors were encountered, ""
+// is returned.
+func (lcfg *LCfg) ErrorText() string {
+	str := ""
+
+	if len(lcfg.InvalidSettings) > 0 {
+		str += "Invalid log definitions detected:"
+		for _, e := range lcfg.InvalidSettings {
+			str += "\n    " + e
+		}
+	}
+
+	if len(lcfg.ModuleConflicts) > 0 {
+		str += "Log module conflicts detected:\n"
+		for mod, logs := range lcfg.ModuleConflicts {
+			for _, l := range logs {
+				str += fmt.Sprintf("    Module=%d Log=%s Package=%s\n",
+					mod, l.Name, l.Source.FullName())
+			}
+		}
+
+		str +=
+			"\nResolve the problem by assigning unique module IDs to each log."
+	}
+
+	return str
+}
+
+// Retrieves a sorted slice of logs from the receiving log configuration.
+func (lcfg *LCfg) sortedLogs() []Log {
+	names := make([]string, 0, len(lcfg.Logs))
+
+	for n, _ := range lcfg.Logs {
+		names = append(names, n)
+	}
+	sort.Strings(names)
+
+	logs := make([]Log, 0, len(names))
+	for _, n := range names {
+		logs = append(logs, lcfg.Logs[n])
+	}
+
+	return logs
+}
+
+// Writes a no-op stub log C macro definition.
+func writeLogStub(logName string, levelStr string, w io.Writer) {
+	fmt.Fprintf(w, "#define %s_%s(...) IGNORE(__VA_ARGS__)\n",
+		logName, levelStr)
+}
+
+// Writes a log C macro definition.
+func writeLogMacro(logName string, module int, levelStr string, w io.Writer) {
+	fmt.Fprintf(w,
+		"#define %s_%s(...) MODLOG_%s(%d, __VA_ARGS__)\n",
+		logName, levelStr, levelStr, module)
+}
+
+// Write log C macro definitions for each log in the log configuration.
+func (lcfg *LCfg) writeLogMacros(w io.Writer) {
+	logs := lcfg.sortedLogs()
+	for _, l := range logs {
+		fmt.Fprintf(w, "\n")
+
+		levelInt, _ := util.AtoiNoOct(l.Level.Value)
+		for i, levelStr := range logLevelNames {
+			if i < levelInt {
+				writeLogStub(l.Name, levelStr, w)
+			} else {
+				modInt, _ := l.Module.IntVal()
+				writeLogMacro(l.Name, modInt, levelStr, w)
+			}
+		}
+	}
+}
+
+// Writes a logcfg header file to the specified writer.
+func (lcfg *LCfg) write(w io.Writer) {
+	fmt.Fprintf(w, newtutil.GeneratedPreamble())
+
+	fmt.Fprintf(w, "#ifndef H_MYNEWT_LOGCFG_\n")
+	fmt.Fprintf(w, "#define H_MYNEWT_LOGCFG_\n\n")
+
+	if len(lcfg.Logs) > 0 {
+		fmt.Fprintf(w, "#include \"modlog/modlog.h\"\n")
+		fmt.Fprintf(w, "#include \"log_common/log_common.h\"\n")
+
+		lcfg.writeLogMacros(w)
+		fmt.Fprintf(w, "\n")
+	}
+
+	fmt.Fprintf(w, "#endif\n")
+}
+
+// Ensures an up-to-date logcfg header is written for the target.
+func (lcfg *LCfg) EnsureWritten(includeDir string) error {
+	buf := bytes.Buffer{}
+	lcfg.write(&buf)
+
+	path := includeDir + "/" + HEADER_PATH
+
+	writeReqd, err := util.FileContentsChanged(path, buf.Bytes())
+	if err != nil {
+		return err
+	}
+	if !writeReqd {
+		log.Debugf("logcfg unchanged; not writing header file (%s).", path)
+		return nil
+	}
+
+	log.Debugf("logcfg changed; writing header file (%s).", path)
+
+	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+		return util.NewNewtError(err.Error())
+	}
+
+	if err := ioutil.WriteFile(path, buf.Bytes(), 0644); err != nil {
+		return util.NewNewtError(err.Error())
+	}
+
+	return nil
+}
diff --git a/newt/pkg/localpackage.go b/newt/pkg/localpackage.go
index d5cc9a81..0b230360 100644
--- a/newt/pkg/localpackage.go
+++ b/newt/pkg/localpackage.go
@@ -26,7 +26,6 @@ import (
 	"io/ioutil"
 	"os"
 	"path/filepath"
-	"strconv"
 	"strings"
 
 	log "github.com/Sirupsen/logrus"
@@ -61,10 +60,6 @@ type LocalPackage struct {
 	// General information about the package
 	desc *PackageDesc
 
-	// Package init function name and stage.  These are used to generate the
-	// sysinit C file.
-	init map[string]int
-
 	// Extra package-specific settings that don't come from syscfg.  For
 	// example, SELFTEST gets set when the newt test command is used.
 	injectedSettings map[string]string
@@ -86,7 +81,6 @@ func NewLocalPackage(r *repo.Repo, pkgDir string) *LocalPackage {
 		SyscfgY:          ycfg.YCfg{},
 		repo:             r,
 		basePath:         filepath.ToSlash(filepath.Clean(pkgDir)),
-		init:             map[string]int{},
 		injectedSettings: map[string]string{},
 	}
 	return pkg
@@ -352,23 +346,6 @@ func (pkg *LocalPackage) Load() error {
 		return nil
 	}
 
-	init := pkg.PkgY.GetValStringMapString("pkg.init", nil)
-	for name, stageStr := range init {
-		stage, err := strconv.ParseInt(stageStr, 10, 64)
-		if err != nil {
-			return util.NewNewtError(fmt.Sprintf("Parsing pkg %s config: %s",
-				pkg.FullName(), err.Error()))
-		}
-		pkg.init[name] = int(stage)
-	}
-
-	// Backwards compatibility: allow old sysinit notation.
-	initFnName := pkg.PkgY.GetValString("pkg.init_function", nil)
-	initStage := pkg.PkgY.GetValInt("pkg.init_stage", nil)
-	if initFnName != "" {
-		pkg.init[initFnName] = initStage
-	}
-
 	// Read the package description from the file
 	pkg.desc, err = pkg.readDesc(pkg.PkgY)
 	if err != nil {
@@ -388,28 +365,18 @@ func (pkg *LocalPackage) Load() error {
 	return nil
 }
 
-func (pkg *LocalPackage) Init() map[string]int {
-	return pkg.init
+func (pkg *LocalPackage) InitFuncs(
+	settings map[string]string) map[string]string {
+
+	return pkg.PkgY.GetValStringMapString("pkg.init", settings)
 }
 
 // DownFuncs retrieves the package's shutdown functions.  The returned map has:
 // key=C-function-name, value=numeric-stage.
 func (pkg *LocalPackage) DownFuncs(
-	settings map[string]string) (map[string]int, error) {
-
-	downFuncs := map[string]int{}
-
-	down := pkg.PkgY.GetValStringMapString("pkg.down", settings)
-	for name, stageStr := range down {
-		stage, err := strconv.ParseInt(stageStr, 10, 64)
-		if err != nil {
-			return nil, util.FmtNewtError("Parsing pkg %s config: %s",
-				pkg.FullName(), err.Error())
-		}
-		downFuncs[name] = int(stage)
-	}
+	settings map[string]string) map[string]string {
 
-	return downFuncs, nil
+	return pkg.PkgY.GetValStringMapString("pkg.down", settings)
 }
 
 func (pkg *LocalPackage) InjectedSettings() map[string]string {
diff --git a/newt/resolve/resolve.go b/newt/resolve/resolve.go
index dcdb0a37..29dcee53 100644
--- a/newt/resolve/resolve.go
+++ b/newt/resolve/resolve.go
@@ -27,11 +27,14 @@ import (
 	log "github.com/Sirupsen/logrus"
 
 	"mynewt.apache.org/newt/newt/flash"
+	"mynewt.apache.org/newt/newt/logcfg"
 	"mynewt.apache.org/newt/newt/pkg"
 	"mynewt.apache.org/newt/newt/project"
 	"mynewt.apache.org/newt/newt/syscfg"
-	"mynewt.apache.org/newt/util"
+	"mynewt.apache.org/newt/newt/sysdown"
+	"mynewt.apache.org/newt/newt/sysinit"
 	"mynewt.apache.org/newt/newt/ycfg"
+	"mynewt.apache.org/newt/util"
 )
 
 // Represents a supplied API.
@@ -58,6 +61,9 @@ type Resolver struct {
 	injectedSettings map[string]string
 	flashMap         flash.FlashMap
 	cfg              syscfg.Cfg
+	lcfg             logcfg.LCfg
+	sysinitCfg       sysinit.SysinitCfg
+	sysdownCfg       sysdown.SysdownCfg
 
 	// [api-name][api-supplier]
 	apiConflicts map[string]map[*ResolvePackage]struct{}
@@ -92,7 +98,7 @@ type ResolveSet struct {
 	// Parent resoluion.  Contains this ResolveSet.
 	Res *Resolution
 
-	// All seed pacakges and their dependencies.
+	// All seed packages and their dependencies.
 	Rpkgs []*ResolvePackage
 }
 
@@ -104,6 +110,9 @@ type ApiConflict struct {
 // The result of resolving a target's configuration, APIs, and dependencies.
 type Resolution struct {
 	Cfg             syscfg.Cfg
+	LCfg            logcfg.LCfg
+	SysinitCfg      sysinit.SysinitCfg
+	SysdownCfg      sysdown.SysdownCfg
 	ApiMap          map[string]*ResolvePackage
 	UnsatisfiedApis map[string][]*ResolvePackage
 	ApiConflicts    []ApiConflict
@@ -540,6 +549,11 @@ func (r *Resolver) resolveDepsAndCfg() error {
 		return err
 	}
 
+	lpkgs := RpkgSliceToLpkgSlice(r.rpkgSlice())
+	r.lcfg = logcfg.Read(lpkgs, &r.cfg)
+	r.sysinitCfg = sysinit.Read(lpkgs, &r.cfg)
+	r.sysdownCfg = sysdown.Read(lpkgs, &r.cfg)
+
 	// Log the final syscfg.
 	r.cfg.Log()
 
@@ -632,6 +646,9 @@ func ResolveFull(
 
 	res := newResolution()
 	res.Cfg = r.cfg
+	res.LCfg = r.lcfg
+	res.SysinitCfg = r.sysinitCfg
+	res.SysdownCfg = r.sysdownCfg
 
 	// Determine which package satisfies each API and which APIs are
 	// unsatisfied.
@@ -748,6 +765,9 @@ func (res *Resolution) ErrorText() string {
 	}
 
 	str += res.Cfg.ErrorText()
+	str += res.LCfg.ErrorText()
+	str += res.SysinitCfg.ErrorText()
+	str += res.SysdownCfg.ErrorText()
 
 	str = strings.TrimSpace(str)
 	if str != "" {
diff --git a/newt/stage/stage.go b/newt/stage/stage.go
index ee2deadd..e7012500 100644
--- a/newt/stage/stage.go
+++ b/newt/stage/stage.go
@@ -36,17 +36,43 @@ import (
 	log "github.com/Sirupsen/logrus"
 
 	"mynewt.apache.org/newt/newt/pkg"
+	"mynewt.apache.org/newt/newt/syscfg"
+	"mynewt.apache.org/newt/newt/val"
 	"mynewt.apache.org/newt/util"
 )
 
 type StageFunc struct {
-	Stage      int
+	Stage      val.ValSetting
 	Name       string
 	ReturnType string
 	ArgList    string
 	Pkg        *pkg.LocalPackage
 }
 
+func NewStageFunc(name string, textVal string,
+	p *pkg.LocalPackage, cfg *syscfg.Cfg) (StageFunc, error) {
+
+	vs, err := val.ResolveValSetting(textVal, cfg)
+	if err != nil {
+		return StageFunc{}, err
+	}
+
+	// Ensure setting resolves to an integer.
+	if _, err := vs.IntVal(); err != nil {
+		return StageFunc{}, util.FmtNewtError("Invalid stage setting: %s=%s; "+
+			"value does not resolve to an integer",
+			name, textVal)
+	}
+
+	sf := StageFunc{
+		Name:  name,
+		Stage: vs,
+		Pkg:   p,
+	}
+
+	return sf, nil
+}
+
 type stageFuncSorter struct {
 	// Used in logging; either "sysinit" or "sysdown".
 	funcType string
@@ -66,10 +92,13 @@ func (s stageFuncSorter) Less(i, j int) bool {
 	a := s.fns[i]
 	b := s.fns[j]
 
+	inta, _ := a.Stage.IntVal()
+	intb, _ := b.Stage.IntVal()
+
 	// 1: Sort by stage number.
-	if a.Stage < b.Stage {
+	if inta < intb {
 		return true
-	} else if b.Stage < a.Stage {
+	} else if intb < inta {
 		return false
 	}
 
@@ -130,20 +159,22 @@ func WriteCalls(sortedFuncs []StageFunc, argList string, w io.Writer) {
 	dupCount := 0
 
 	for i, f := range sortedFuncs {
-		if f.Stage != prevStage {
-			prevStage = f.Stage
+		intStage, _ := f.Stage.IntVal()
+
+		if intStage != prevStage {
+			prevStage = intStage
 			dupCount = 0
 
 			if i != 0 {
 				fmt.Fprintf(w, "\n")
 			}
-			fmt.Fprintf(w, "    /*** Stage %d */\n", f.Stage)
+			fmt.Fprintf(w, "    /*** Stage %d */\n", intStage)
 		} else {
 			dupCount += 1
 		}
 
 		fmt.Fprintf(w, "    /* %d.%d: %s (%s) */\n",
-			f.Stage, dupCount, f.Name, f.Pkg.Name())
+			intStage, dupCount, f.Name, f.Pkg.Name())
 		fmt.Fprintf(w, "    %s(%s);\n", f.Name, argList)
 	}
 }
@@ -156,20 +187,22 @@ func WriteArr(sortedFuncs []StageFunc, w io.Writer) {
 	dupCount := 0
 
 	for i, f := range sortedFuncs {
-		if f.Stage != prevStage {
-			prevStage = f.Stage
+		intStage, _ := f.Stage.IntVal()
+
+		if intStage != prevStage {
+			prevStage = intStage
 			dupCount = 0
 
 			if i != 0 {
 				fmt.Fprintf(w, "\n")
 			}
-			fmt.Fprintf(w, "    /*** Stage %d */\n", f.Stage)
+			fmt.Fprintf(w, "    /*** Stage %d */\n", intStage)
 		} else {
 			dupCount += 1
 		}
 
 		fmt.Fprintf(w, "    /* %d.%d: %s (%s) */\n",
-			f.Stage, dupCount, f.Name, f.Pkg.Name())
+			intStage, dupCount, f.Name, f.Pkg.Name())
 		fmt.Fprintf(w, "    %s,\n", f.Name)
 	}
 	fmt.Fprintf(w, "\n")
diff --git a/newt/syscfg/syscfg.go b/newt/syscfg/syscfg.go
index 6e75a842..40f68b30 100644
--- a/newt/syscfg/syscfg.go
+++ b/newt/syscfg/syscfg.go
@@ -68,6 +68,8 @@ const SYSCFG_PRIO_ANY = "any"
 // Reserve last 16 priorities for the system (sanity, idle).
 const SYSCFG_TASK_PRIO_MAX = 0xef
 
+var cfgRefRe = regexp.MustCompile("MYNEWT_VAL\\((\\w+)\\)")
+
 var cfgSettingNameTypeMap = map[string]CfgSettingType{
 	"raw":           CFG_SETTING_TYPE_RAW,
 	"task_priority": CFG_SETTING_TYPE_TASK_PRIO,
@@ -180,34 +182,50 @@ func (cfg *Cfg) SettingValues() map[string]string {
 	return values
 }
 
-func (cfg *Cfg) ResolveValueRefs() {
-	re := regexp.MustCompile("MYNEWT_VAL\\((\\w+)\\)")
-	for k, entry := range cfg.Settings {
-		value := strings.TrimSpace(entry.Value)
-
-		m := re.FindStringSubmatch(value)
-		if len(m) == 0 || len(m[0]) != len(value) {
-			// either there is no reference or there's something else besides
-			// reference - skip it
-			// TODO we may want to emit warning in the latter case (?)
-			continue
-		}
+func ResolveValueRefName(val string) string {
+	// If the value has the `MYNEWT_VAL([...])` notation, then extract the
+	// parenthesized identifier.
+	m := cfgRefRe.FindStringSubmatch(val)
+	if m == nil {
+		return ""
+	} else {
+		// TODO we may try to resolve nested references...
+		return m[1]
+	}
+}
 
-		newName := m[1]
+func (cfg *Cfg) ExpandRef(val string) (string, string, error) {
+	refName := ResolveValueRefName(val)
+	if refName == "" {
+		// Not a reference.
+		return "", val, nil
+	}
 
-		// TODO we may try to resolve nested references...
+	entry, ok := cfg.Settings[refName]
+	if !ok {
+		return "", "", util.FmtNewtError(
+			"setting value \"%s\" references undefined setting", val)
+	}
 
-		newEntry, exists := cfg.Settings[newName]
-		entry.ValueRefName = newName
-		if exists {
-			entry.Value = newEntry.Value
-		} else {
-			// set unresolved setting value to 0, this way restrictions
-			// can be evaluated and won't create spurious warnings
+	return entry.Name, entry.Value, nil
+
+}
+
+func (cfg *Cfg) ResolveValueRefs() {
+	for k, entry := range cfg.Settings {
+		refName, val, err := cfg.ExpandRef(strings.TrimSpace(entry.Value))
+		if err != nil {
+			// Referenced setting doesn't exist.  Set unresolved setting value
+			// to 0, this way restrictions can be evaluated and won't create
+			// spurious warnings.
 			entry.Value = "0"
 			cfg.UnresolvedValueRefs[k] = struct{}{}
+			cfg.Settings[k] = entry
+		} else if refName != "" {
+			entry.ValueRefName = refName
+			entry.Value = val
+			cfg.Settings[k] = entry
 		}
-		cfg.Settings[k] = entry
 	}
 }
 
diff --git a/newt/sysdown/sysdown.go b/newt/sysdown/sysdown.go
index 060130e6..b240edf0 100644
--- a/newt/sysdown/sysdown.go
+++ b/newt/sysdown/sysdown.go
@@ -30,68 +30,156 @@ import (
 	"mynewt.apache.org/newt/newt/syscfg"
 )
 
-// downFuncs collects the sysdown functions corresponding to the provided
-// packages.
-func downFuncs(pkgs []*pkg.LocalPackage,
-	cfg syscfg.Cfg) ([]stage.StageFunc, error) {
-
-	fns := make([]stage.StageFunc, 0, len(pkgs))
-	for _, p := range pkgs {
-		downMap, err := p.DownFuncs(cfg.AllSettingsForLpkg(p))
+type SysdownCfg struct {
+	// Sorted in call order (stage-num,function-name).
+	StageFuncs []stage.StageFunc
+
+	// Strings describing errors encountered while parsing the sysdown config.
+	InvalidSettings []string
+
+	// Contains sets of entries with conflicting function names.
+	//     [function-name] => <slice-of-stages-with-function-name>
+	Conflicts map[string][]stage.StageFunc
+}
+
+func (scfg *SysdownCfg) readOnePkg(lpkg *pkg.LocalPackage, cfg *syscfg.Cfg) {
+	settings := cfg.AllSettingsForLpkg(lpkg)
+	initMap := lpkg.DownFuncs(settings)
+	for name, stageStr := range initMap {
+		sf, err := stage.NewStageFunc(name, stageStr, lpkg, cfg)
 		if err != nil {
-			return nil, err
+			scfg.InvalidSettings = append(scfg.InvalidSettings, err.Error())
 		}
+		sf.ReturnType = "int"
+		sf.ArgList = "int reason"
 
-		for name, stageNum := range downMap {
-			fn := stage.StageFunc{
-				Name:       name,
-				Stage:      stageNum,
-				ReturnType: "int",
-				ArgList:    "int reason",
-				Pkg:        p,
-			}
-			fns = append(fns, fn)
+		scfg.StageFuncs = append(scfg.StageFuncs, sf)
+	}
+}
+
+// Searches the sysdown configuration for entries with identical function
+// names.  The sysdown configuration object is populated with the results.
+func (scfg *SysdownCfg) detectConflicts() {
+	m := map[string][]stage.StageFunc{}
+
+	for _, sf := range scfg.StageFuncs {
+		m[sf.Name] = append(m[sf.Name], sf)
+	}
+
+	for name, sfs := range m {
+		if len(sfs) > 1 {
+			scfg.Conflicts[name] = sfs
 		}
 	}
+}
+
+func Read(lpkgs []*pkg.LocalPackage, cfg *syscfg.Cfg) SysdownCfg {
+	scfg := SysdownCfg{}
+
+	for _, lpkg := range lpkgs {
+		scfg.readOnePkg(lpkg, cfg)
+	}
+
+	scfg.detectConflicts()
+	stage.SortStageFuncs(scfg.StageFuncs, "sysdown")
 
-	return fns, nil
+	return scfg
 }
 
-func sortedDownFuncs(pkgs []*pkg.LocalPackage,
-	cfg syscfg.Cfg) ([]stage.StageFunc, error) {
+func (scfg *SysdownCfg) filter(lpkgs []*pkg.LocalPackage) []stage.StageFunc {
+	m := make(map[*pkg.LocalPackage]struct{}, len(lpkgs))
 
-	fns, err := downFuncs(pkgs, cfg)
-	if err != nil {
-		return nil, err
+	for _, lpkg := range lpkgs {
+		m[lpkg] = struct{}{}
 	}
 
-	stage.SortStageFuncs(fns, "sysdown")
-	return fns, nil
+	filtered := []stage.StageFunc{}
+	for _, sf := range scfg.StageFuncs {
+		if _, ok := m[sf.Pkg]; ok {
+			filtered = append(filtered, sf)
+		}
+	}
+
+	return filtered
 }
 
-func write(pkgs []*pkg.LocalPackage, cfg syscfg.Cfg, w io.Writer) error {
+// If any errors were encountered while parsing sysdown definitions, this
+// function returns a string indicating the errors.  If no errors were
+// encountered, "" is returned.
+func (scfg *SysdownCfg) ErrorText() string {
+	str := ""
+
+	if len(scfg.InvalidSettings) > 0 {
+		str += "Invalid sysdown definitions detected:"
+		for _, e := range scfg.InvalidSettings {
+			str += "\n    " + e
+		}
+	}
+
+	if len(scfg.Conflicts) > 0 {
+		str += "Sysdown function name conflicts detected:\n"
+		for name, sfs := range scfg.Conflicts {
+			for _, sf := range sfs {
+				str += fmt.Sprintf("    Function=%s Package=%s\n",
+					name, sf.Pkg.FullName())
+			}
+		}
+
+		str += "\nResolve the problem by assigning unique function names " +
+			"to each entry."
+	}
+
+	return str
+}
+
+func (scfg *SysdownCfg) write(lpkgs []*pkg.LocalPackage, isLoader bool,
+	w io.Writer) error {
+
+	var sfs []stage.StageFunc
+	if lpkgs == nil {
+		sfs = scfg.StageFuncs
+	} else {
+		sfs = scfg.filter(lpkgs)
+	}
+
 	fmt.Fprintf(w, newtutil.GeneratedPreamble())
 
-	fns, err := sortedDownFuncs(pkgs, cfg)
-	if err != nil {
-		return err
+	if isLoader {
+		fmt.Fprintf(w, "#if SPLIT_LOADER\n\n")
+	} else {
+		fmt.Fprintf(w, "#if !SPLIT_LOADER\n\n")
 	}
 
-	stage.WritePrototypes(fns, w)
+	stage.WritePrototypes(sfs, w)
+
+	var arrName string
+
+	// XXX: Assign a different array name depending on isLoader.
+	arrName = "sysdown_cbs"
 
-	fmt.Fprintf(w, "\nint (* const sysdown_cbs[])(int reason) = {\n")
-	stage.WriteArr(fns, w)
+	fmt.Fprintf(w, "\nint (* const %s[])(int reason) = {\n", arrName)
+	stage.WriteArr(sfs, w)
 	fmt.Fprintf(w, "};\n")
 
+	fmt.Fprintf(w, "#endif\n")
+
 	return nil
 }
 
-func EnsureWritten(pkgs []*pkg.LocalPackage, cfg syscfg.Cfg, srcDir string,
-	targetName string) error {
+func (scfg *SysdownCfg) EnsureWritten(lpkgs []*pkg.LocalPackage, srcDir string,
+	targetName string, isLoader bool) error {
 
 	buf := bytes.Buffer{}
-	write(pkgs, cfg, &buf)
+	if err := scfg.write(lpkgs, isLoader, &buf); err != nil {
+		return err
+	}
+
+	var path string
+	if isLoader {
+		path = fmt.Sprintf("%s/%s-sysdown-loader.c", srcDir, targetName)
+	} else {
+		path = fmt.Sprintf("%s/%s-sysdown-app.c", srcDir, targetName)
+	}
 
-	path := fmt.Sprintf("%s/%s-sysdown.c", srcDir, targetName)
 	return stage.EnsureWritten(path, buf.Bytes())
 }
diff --git a/newt/sysinit/sysinit.go b/newt/sysinit/sysinit.go
index 98e7fc65..7d012d0d 100644
--- a/newt/sysinit/sysinit.go
+++ b/newt/sysinit/sysinit.go
@@ -27,33 +27,118 @@ import (
 	"mynewt.apache.org/newt/newt/newtutil"
 	"mynewt.apache.org/newt/newt/pkg"
 	"mynewt.apache.org/newt/newt/stage"
+	"mynewt.apache.org/newt/newt/syscfg"
 )
 
-func initFuncs(pkgs []*pkg.LocalPackage) []stage.StageFunc {
-	fns := make([]stage.StageFunc, 0, len(pkgs))
-	for _, p := range pkgs {
-		initMap := p.Init()
-		for name, stageNum := range initMap {
-			fn := stage.StageFunc{
-				Name:  name,
-				Stage: stageNum,
-				Pkg:   p,
-			}
-			fns = append(fns, fn)
+type SysinitCfg struct {
+	// Sorted in call order (stage-num,function-name).
+	StageFuncs []stage.StageFunc
+
+	// Strings describing errors encountered while parsing the sysinit config.
+	InvalidSettings []string
+
+	// Contains sets of entries with conflicting function names.
+	//     [function-name] => <slice-of-stages-with-function-name>
+	Conflicts map[string][]stage.StageFunc
+}
+
+func (scfg *SysinitCfg) readOnePkg(lpkg *pkg.LocalPackage, cfg *syscfg.Cfg) {
+	settings := cfg.AllSettingsForLpkg(lpkg)
+	initMap := lpkg.InitFuncs(settings)
+	for name, stageStr := range initMap {
+		sf, err := stage.NewStageFunc(name, stageStr, lpkg, cfg)
+		if err != nil {
+			scfg.InvalidSettings = append(scfg.InvalidSettings, err.Error())
 		}
+
+		scfg.StageFuncs = append(scfg.StageFuncs, sf)
 	}
+}
+
+// Searches the sysinit configuration for entries with identical function
+// names.  The sysinit configuration object is populated with the results.
+func (scfg *SysinitCfg) detectConflicts() {
+	m := map[string][]stage.StageFunc{}
 
-	return fns
+	for _, sf := range scfg.StageFuncs {
+		m[sf.Name] = append(m[sf.Name], sf)
+	}
+
+	for name, sfs := range m {
+		if len(sfs) > 1 {
+			scfg.Conflicts[name] = sfs
+		}
+	}
 }
 
-func sortedInitFuncs(pkgs []*pkg.LocalPackage) []stage.StageFunc {
-	fns := initFuncs(pkgs)
-	stage.SortStageFuncs(fns, "sysinit")
-	return fns
+func Read(lpkgs []*pkg.LocalPackage, cfg *syscfg.Cfg) SysinitCfg {
+	scfg := SysinitCfg{}
+
+	for _, lpkg := range lpkgs {
+		scfg.readOnePkg(lpkg, cfg)
+	}
+
+	scfg.detectConflicts()
+	stage.SortStageFuncs(scfg.StageFuncs, "sysinit")
+
+	return scfg
 }
 
-func write(pkgs []*pkg.LocalPackage, isLoader bool,
-	w io.Writer) {
+func (scfg *SysinitCfg) filter(lpkgs []*pkg.LocalPackage) []stage.StageFunc {
+	m := make(map[*pkg.LocalPackage]struct{}, len(lpkgs))
+
+	for _, lpkg := range lpkgs {
+		m[lpkg] = struct{}{}
+	}
+
+	filtered := []stage.StageFunc{}
+	for _, sf := range scfg.StageFuncs {
+		if _, ok := m[sf.Pkg]; ok {
+			filtered = append(filtered, sf)
+		}
+	}
+
+	return filtered
+}
+
+// If any errors were encountered while parsing sysinit definitions, this
+// function returns a string indicating the errors.  If no errors were
+// encountered, "" is returned.
+func (scfg *SysinitCfg) ErrorText() string {
+	str := ""
+
+	if len(scfg.InvalidSettings) > 0 {
+		str += "Invalid sysinit definitions detected:"
+		for _, e := range scfg.InvalidSettings {
+			str += "\n    " + e
+		}
+	}
+
+	if len(scfg.Conflicts) > 0 {
+		str += "Sysinit function name conflicts detected:\n"
+		for name, sfs := range scfg.Conflicts {
+			for _, sf := range sfs {
+				str += fmt.Sprintf("    Function=%s Package=%s\n",
+					name, sf.Pkg.FullName())
+			}
+		}
+
+		str += "\nResolve the problem by assigning unique function names " +
+			"to each entry."
+	}
+
+	return str
+}
+
+func (scfg *SysinitCfg) write(lpkgs []*pkg.LocalPackage, isLoader bool,
+	w io.Writer) error {
+
+	var sfs []stage.StageFunc
+	if lpkgs == nil {
+		sfs = scfg.StageFuncs
+	} else {
+		sfs = scfg.filter(lpkgs)
+	}
 
 	fmt.Fprintf(w, newtutil.GeneratedPreamble())
 
@@ -63,9 +148,7 @@ func write(pkgs []*pkg.LocalPackage, isLoader bool,
 		fmt.Fprintf(w, "#if !SPLIT_LOADER\n\n")
 	}
 
-	fns := sortedInitFuncs(pkgs)
-
-	stage.WritePrototypes(fns, w)
+	stage.WritePrototypes(sfs, w)
 
 	var fnName string
 	if isLoader {
@@ -77,17 +160,21 @@ func write(pkgs []*pkg.LocalPackage, isLoader bool,
 	fmt.Fprintf(w, "\n")
 	fmt.Fprintf(w, "void\n%s(void)\n{\n", fnName)
 
-	stage.WriteCalls(fns, "", w)
+	stage.WriteCalls(sfs, "", w)
 
 	fmt.Fprintf(w, "}\n\n")
 	fmt.Fprintf(w, "#endif\n")
+
+	return nil
 }
 
-func EnsureWritten(pkgs []*pkg.LocalPackage, srcDir string, targetName string,
-	isLoader bool) error {
+func (scfg *SysinitCfg) EnsureWritten(lpkgs []*pkg.LocalPackage, srcDir string,
+	targetName string, isLoader bool) error {
 
 	buf := bytes.Buffer{}
-	write(pkgs, isLoader, &buf)
+	if err := scfg.write(lpkgs, isLoader, &buf); err != nil {
+		return err
+	}
 
 	var path string
 	if isLoader {
diff --git a/newt/val/valsetting.go b/newt/val/valsetting.go
new file mode 100644
index 00000000..a57d1d1a
--- /dev/null
+++ b/newt/val/valsetting.go
@@ -0,0 +1,65 @@
+/**
+ * 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 val
+
+import (
+	"mynewt.apache.org/newt/newt/syscfg"
+	"mynewt.apache.org/newt/util"
+)
+
+// Value setting: represents a setting value as read from a YAML configuration
+// file.  The setting may reference a syscfg setting via the `MYNEWT_VAL(...)`
+// notation.
+type ValSetting struct {
+	// The exact text specified as the YAML map key.
+	Text string
+
+	// If this setting refers to a syscfg setting via the `MYNEWT_VAL(...)`
+	// notation, this contains the name of the setting.  Otherwise, "".
+	RefName string
+
+	// The setting value, after setting references are resolved.
+	Value string
+}
+
+// IntVal Extracts a setting's integer value.
+func (vs *ValSetting) IntVal() (int, error) {
+	iv, err := util.AtoiNoOct(vs.Value)
+	if err != nil {
+		return 0, util.ChildNewtError(err)
+	}
+
+	return iv, nil
+}
+
+// Constructs a setting from a YAML string.
+func ResolveValSetting(s string, cfg *syscfg.Cfg) (ValSetting, error) {
+	refName, val, err := cfg.ExpandRef(s)
+	if err != nil {
+		return ValSetting{},
+			util.FmtNewtError("value \"%s\" references undefined setting", s)
+	}
+
+	return ValSetting{
+		Text:    s,
+		RefName: refName,
+		Value:   val,
+	}, nil
+}


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services