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 2018/10/23 17:47:58 UTC
[mynewt-newt] 01/02: Genericize sysinit functionality
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 484bbb4729ea39ff616f0758358d6fe833d7fb50
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Thu Sep 27 15:18:51 2018 -0700
Genericize sysinit functionality
Create a `stage` package. This package emits C code consisting of
a sequence of function calls.
---
newt/stage/stage.go | 204 ++++++++++++++++++++++++++++++++++++++++++++++++
newt/sysinit/sysinit.go | 163 +++++---------------------------------
util/util.go | 17 ++++
3 files changed, 240 insertions(+), 144 deletions(-)
diff --git a/newt/stage/stage.go b/newt/stage/stage.go
new file mode 100644
index 0000000..ee2dead
--- /dev/null
+++ b/newt/stage/stage.go
@@ -0,0 +1,204 @@
+/**
+ * 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.
+ */
+
+// stage - utility for generating C code consisting of a sequence of function
+// calls ordered by stage number.
+//
+// This package is used by sysinit and sysdown.
+
+package stage
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+
+ log "github.com/Sirupsen/logrus"
+
+ "mynewt.apache.org/newt/newt/pkg"
+ "mynewt.apache.org/newt/util"
+)
+
+type StageFunc struct {
+ Stage int
+ Name string
+ ReturnType string
+ ArgList string
+ Pkg *pkg.LocalPackage
+}
+
+type stageFuncSorter struct {
+ // Used in logging; either "sysinit" or "sysdown".
+ funcType string
+ // Array of functions to be sorted.
+ fns []StageFunc
+}
+
+func (s stageFuncSorter) Len() int {
+ return len(s.fns)
+}
+
+func (s stageFuncSorter) Swap(i, j int) {
+ s.fns[i], s.fns[j] = s.fns[j], s.fns[i]
+}
+
+func (s stageFuncSorter) Less(i, j int) bool {
+ a := s.fns[i]
+ b := s.fns[j]
+
+ // 1: Sort by stage number.
+ if a.Stage < b.Stage {
+ return true
+ } else if b.Stage < a.Stage {
+ return false
+ }
+
+ // 2: Sort by function name.
+ switch strings.Compare(a.Name, b.Name) {
+ case -1:
+ return true
+ case 1:
+ return false
+ }
+
+ // Same stage and function name?
+ log.Warnf("Warning: Identical %s functions detected: %s",
+ s.funcType, a.Name)
+
+ return true
+}
+
+// SortStageFuncs performs an in-place sort of the provided StageFunc slice.
+func SortStageFuncs(unsorted []StageFunc, funcType string) {
+ s := stageFuncSorter{
+ funcType: funcType,
+ fns: unsorted,
+ }
+
+ sort.Sort(s)
+}
+
+func (f *StageFunc) ReturnTypeString() string {
+ if f.ReturnType == "" {
+ return "void"
+ } else {
+ return f.ReturnType
+ }
+}
+
+func (f *StageFunc) ArgListString() string {
+ if f.ArgList == "" {
+ return "void"
+ } else {
+ return f.ArgList
+ }
+}
+
+// WriteCalls emits C code: a list of function prototypes corresponding to the
+// provided slice of stage functions.
+func WritePrototypes(sortedFns []StageFunc, w io.Writer) {
+ for _, f := range sortedFns {
+ fmt.Fprintf(w, "%s %s(%s);\n",
+ f.ReturnTypeString(), f.Name, f.ArgListString())
+ }
+}
+
+// WriteCalls emits C code: a sequence of function calls corresponding to the
+// provided slice of stage functions.
+func WriteCalls(sortedFuncs []StageFunc, argList string, w io.Writer) {
+ prevStage := -1
+ dupCount := 0
+
+ for i, f := range sortedFuncs {
+ if f.Stage != prevStage {
+ prevStage = f.Stage
+ dupCount = 0
+
+ if i != 0 {
+ fmt.Fprintf(w, "\n")
+ }
+ fmt.Fprintf(w, " /*** Stage %d */\n", f.Stage)
+ } else {
+ dupCount += 1
+ }
+
+ fmt.Fprintf(w, " /* %d.%d: %s (%s) */\n",
+ f.Stage, dupCount, f.Name, f.Pkg.Name())
+ fmt.Fprintf(w, " %s(%s);\n", f.Name, argList)
+ }
+}
+
+// WriteArr emits C code: an array body of function pointers represented by the
+// supplied slice. The caller must 1) write the array declaration before
+// calling this function, and 2) write "};" afterwards.
+func WriteArr(sortedFuncs []StageFunc, w io.Writer) {
+ prevStage := -1
+ dupCount := 0
+
+ for i, f := range sortedFuncs {
+ if f.Stage != prevStage {
+ prevStage = f.Stage
+ dupCount = 0
+
+ if i != 0 {
+ fmt.Fprintf(w, "\n")
+ }
+ fmt.Fprintf(w, " /*** Stage %d */\n", f.Stage)
+ } else {
+ dupCount += 1
+ }
+
+ fmt.Fprintf(w, " /* %d.%d: %s (%s) */\n",
+ f.Stage, dupCount, f.Name, f.Pkg.Name())
+ fmt.Fprintf(w, " %s,\n", f.Name)
+ }
+ fmt.Fprintf(w, "\n")
+ fmt.Fprintf(w, " /*** Array terminator. */\n")
+ fmt.Fprintf(w, " 0\n")
+}
+
+// EnsureWritten writes the specified file if its contents differ from those of
+// the supplied byte slice.
+func EnsureWritten(path string, contents []byte) error {
+ unchanged, err := util.FileContains(contents, path)
+ if err != nil {
+ return err
+ }
+
+ if unchanged {
+ log.Debugf("file unchanged; not writing src file (%s).", path)
+ return nil
+ }
+
+ log.Debugf("file changed; writing src file (%s).", path)
+
+ if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+ return util.NewNewtError(err.Error())
+ }
+
+ if err := ioutil.WriteFile(path, contents, 0644); err != nil {
+ return util.NewNewtError(err.Error())
+ }
+
+ return nil
+}
diff --git a/newt/sysinit/sysinit.go b/newt/sysinit/sysinit.go
index 4071a09..98e7fc6 100644
--- a/newt/sysinit/sysinit.go
+++ b/newt/sysinit/sysinit.go
@@ -23,125 +23,33 @@ import (
"bytes"
"fmt"
"io"
- "io/ioutil"
- "os"
- "path/filepath"
- "sort"
- "strings"
-
- log "github.com/Sirupsen/logrus"
"mynewt.apache.org/newt/newt/newtutil"
"mynewt.apache.org/newt/newt/pkg"
- "mynewt.apache.org/newt/util"
+ "mynewt.apache.org/newt/newt/stage"
)
-type initFunc struct {
- stage int
- name string
- pkg *pkg.LocalPackage
-}
-
-func buildStageMap(pkgs []*pkg.LocalPackage) map[int][]*initFunc {
- sm := map[int][]*initFunc{}
-
- for _, p := range pkgs {
- for name, stage := range p.Init() {
- initFunc := &initFunc{
- stage: stage,
- name: name,
- pkg: p,
- }
- sm[stage] = append(sm[stage], initFunc)
- }
- }
-
- return sm
-}
-
-type initFuncSorter struct {
- fns []*initFunc
-}
-
-func (s initFuncSorter) Len() int {
- return len(s.fns)
-}
-func (s initFuncSorter) Swap(i, j int) {
- s.fns[i], s.fns[j] = s.fns[j], s.fns[i]
-}
-func (s initFuncSorter) Less(i, j int) bool {
- a := s.fns[i]
- b := s.fns[j]
-
- // 1: Sort by stage number.
- if a.stage < b.stage {
- return true
- } else if b.stage < a.stage {
- return false
- }
-
- // 2: Sort by function name.
- switch strings.Compare(a.name, b.name) {
- case -1:
- return true
- case 1:
- return false
- }
-
- // Same stage and function name?
- log.Warnf("Warning: Identical sysinit functions detected: %s", a.name)
- return true
-}
-
-func sortedInitFuncs(pkgs []*pkg.LocalPackage) []*initFunc {
- sorter := initFuncSorter{
- fns: make([]*initFunc, 0, len(pkgs)),
- }
-
+func initFuncs(pkgs []*pkg.LocalPackage) []stage.StageFunc {
+ fns := make([]stage.StageFunc, 0, len(pkgs))
for _, p := range pkgs {
initMap := p.Init()
- for name, stage := range initMap {
- fn := &initFunc{
- name: name,
- stage: stage,
- pkg: p,
+ for name, stageNum := range initMap {
+ fn := stage.StageFunc{
+ Name: name,
+ Stage: stageNum,
+ Pkg: p,
}
- sorter.fns = append(sorter.fns, fn)
+ fns = append(fns, fn)
}
}
- sort.Sort(sorter)
- return sorter.fns
-}
-
-func writePrototypes(pkgs []*pkg.LocalPackage, w io.Writer) {
- sortedFns := sortedInitFuncs(pkgs)
- for _, f := range sortedFns {
- fmt.Fprintf(w, "void %s(void);\n", f.name)
- }
+ return fns
}
-func writeCalls(sortedInitFuncs []*initFunc, w io.Writer) {
- prevStage := -1
- dupCount := 0
-
- for i, f := range sortedInitFuncs {
- if f.stage != prevStage {
- prevStage = f.stage
- dupCount = 0
-
- if i != 0 {
- fmt.Fprintf(w, "\n")
- }
- fmt.Fprintf(w, " /*** Stage %d */\n", f.stage)
- } else {
- dupCount += 1
- }
-
- fmt.Fprintf(w, " /* %d.%d: %s (%s) */\n",
- f.stage, dupCount, f.name, f.pkg.Name())
- fmt.Fprintf(w, " %s();\n", f.name)
- }
+func sortedInitFuncs(pkgs []*pkg.LocalPackage) []stage.StageFunc {
+ fns := initFuncs(pkgs)
+ stage.SortStageFuncs(fns, "sysinit")
+ return fns
}
func write(pkgs []*pkg.LocalPackage, isLoader bool,
@@ -155,7 +63,9 @@ func write(pkgs []*pkg.LocalPackage, isLoader bool,
fmt.Fprintf(w, "#if !SPLIT_LOADER\n\n")
}
- writePrototypes(pkgs, w)
+ fns := sortedInitFuncs(pkgs)
+
+ stage.WritePrototypes(fns, w)
var fnName string
if isLoader {
@@ -167,27 +77,12 @@ func write(pkgs []*pkg.LocalPackage, isLoader bool,
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "void\n%s(void)\n{\n", fnName)
- writeCalls(sortedInitFuncs(pkgs), w)
+ stage.WriteCalls(fns, "", w)
fmt.Fprintf(w, "}\n\n")
fmt.Fprintf(w, "#endif\n")
}
-func writeRequired(contents []byte, path string) (bool, error) {
- oldSrc, err := ioutil.ReadFile(path)
- if err != nil {
- if os.IsNotExist(err) {
- // File doesn't exist; write required.
- return true, nil
- }
-
- return true, util.NewNewtError(err.Error())
- }
-
- rc := bytes.Compare(oldSrc, contents)
- return rc != 0, nil
-}
-
func EnsureWritten(pkgs []*pkg.LocalPackage, srcDir string, targetName string,
isLoader bool) error {
@@ -201,25 +96,5 @@ func EnsureWritten(pkgs []*pkg.LocalPackage, srcDir string, targetName string,
path = fmt.Sprintf("%s/%s-sysinit-app.c", srcDir, targetName)
}
- writeReqd, err := writeRequired(buf.Bytes(), path)
- if err != nil {
- return err
- }
-
- if !writeReqd {
- log.Debugf("sysinit unchanged; not writing src file (%s).", path)
- return nil
- }
-
- log.Debugf("sysinit changed; writing src 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
+ return stage.EnsureWritten(path, buf.Bytes())
}
diff --git a/util/util.go b/util/util.go
index e848642..d3abfc3 100644
--- a/util/util.go
+++ b/util/util.go
@@ -696,3 +696,20 @@ func StringMapStringToItfMapItf(
return imi
}
+
+// FileContains indicates whether the specified file's contents are equal to
+// the provided byte slice.
+func FileContains(contents []byte, path string) (bool, error) {
+ oldSrc, err := ioutil.ReadFile(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ // File doesn't exist; contents aren't equal.
+ return false, nil
+ }
+
+ return false, NewNewtError(err.Error())
+ }
+
+ rc := bytes.Compare(oldSrc, contents)
+ return rc == 0, nil
+}