This is an automated email from the ASF dual-hosted git repository. ccollins pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-newt.git
commit 31417de60e9b39d5f2a7ba5130b150b5317b088f Author: Christopher Collins <ccoll...@apache.org> AuthorDate: Wed Oct 24 17:03:58 2018 -0700 Higher level structures for sysinit/sysdown Prior to this commit, the sysinit and sysdown function lists were created on demand, when the corresponding C code is generated. This commit causes the sysinit and sysdown configurations to be generated at resolution time. This allows: * Better error reporting * CLI commands to access the sysinit / sysdown configuration --- newt/builder/targetbuild.go | 77 ++++++++------------- newt/pkg/localpackage.go | 45 ++---------- newt/resolve/resolve.go | 14 +++- newt/sysdown/sysdown.go | 162 ++++++++++++++++++++++++++++++++++---------- newt/sysinit/sysinit.go | 137 ++++++++++++++++++++++++++++++------- 5 files changed, 285 insertions(+), 150 deletions(-) diff --git a/newt/builder/targetbuild.go b/newt/builder/targetbuild.go index 519632c..9ee7317 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" @@ -216,72 +214,59 @@ func (t *TargetBuilder) validateAndWriteCfg() error { log.Warn(line) } - if err := syscfg.EnsureWritten(t.res.Cfg, - GeneratedIncludeDir(t.target.Name())); err != nil { - - return err - } - - if err := t.res.LCfg.EnsureWritten( - 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) - - return nil -} + if err := t.res.SysinitCfg.EnsureWritten(lpkgs, srcDir, + pkg.ShortName(t.target.Package()), false); err != 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 } @@ -339,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/pkg/localpackage.go b/newt/pkg/localpackage.go index d5cc9a8..0b23036 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 b5fa87a..29dcee5 100644 --- a/newt/resolve/resolve.go +++ b/newt/resolve/resolve.go @@ -31,6 +31,8 @@ import ( "mynewt.apache.org/newt/newt/pkg" "mynewt.apache.org/newt/newt/project" "mynewt.apache.org/newt/newt/syscfg" + "mynewt.apache.org/newt/newt/sysdown" + "mynewt.apache.org/newt/newt/sysinit" "mynewt.apache.org/newt/newt/ycfg" "mynewt.apache.org/newt/util" ) @@ -60,6 +62,8 @@ type Resolver struct { 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{} @@ -94,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 } @@ -107,6 +111,8 @@ type ApiConflict struct { 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 @@ -545,6 +551,8 @@ func (r *Resolver) resolveDepsAndCfg() error { 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() @@ -639,6 +647,8 @@ 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. @@ -756,6 +766,8 @@ 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/sysdown/sysdown.go b/newt/sysdown/sysdown.go index 060130e..b240edf 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 98e7fc6..7d012d0 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 {