Repository: incubator-mynewt-newt Updated Branches: refs/heads/develop 10b0ce6bd -> 327dfae4c
newt syscfg / sysinit. Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/commit/0ae71ef1 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/tree/0ae71ef1 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/diff/0ae71ef1 Branch: refs/heads/develop Commit: 0ae71ef1a900bba44936069d053f90d8797c8650 Parents: 0baf3a3 Author: Christopher Collins <ccoll...@apache.org> Authored: Mon Sep 12 20:35:34 2016 -0700 Committer: Christopher Collins <ccoll...@apache.org> Committed: Mon Sep 12 20:35:34 2016 -0700 ---------------------------------------------------------------------- newt/Godeps/Godeps.json | 14 +- newt/builder/build.go | 270 ++++--- newt/builder/buildpackage.go | 102 +-- newt/builder/buildutil.go | 36 +- newt/builder/load.go | 3 +- newt/builder/targetbuild.go | 12 +- newt/cli/build_cmds.go | 127 ++- newt/cli/complete_cmd.go | 32 +- newt/cli/target_cmds.go | 109 ++- newt/newt.go | 8 +- newt/newtutil/newtutil.go | 72 +- newt/pkg/localpackage.go | 62 +- newt/pkg/package.go | 5 +- newt/pkg/packageutil.go | 32 + newt/project/project.go | 2 - newt/syscfg/syscfg.go | 801 +++++++++++++++++++ newt/sysinit/sysinit.go | 154 ++++ newt/toolchain/compiler.go | 6 +- newt/toolchain/deps.go | 8 + newt/vendor/mynewt.apache.org/newt/DISCLAIMER | 8 - newt/vendor/mynewt.apache.org/newt/LICENSE | 244 ------ newt/vendor/mynewt.apache.org/newt/NOTICE | 8 - newt/vendor/mynewt.apache.org/newt/util/util.go | 21 + 23 files changed, 1556 insertions(+), 580 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/Godeps/Godeps.json ---------------------------------------------------------------------- diff --git a/newt/Godeps/Godeps.json b/newt/Godeps/Godeps.json index cf4c345..4dcc675 100644 --- a/newt/Godeps/Godeps.json +++ b/newt/Godeps/Godeps.json @@ -1,7 +1,7 @@ { "ImportPath": "mynewt.apache.org/newt/newt", "GoVersion": "go1.6", - "GodepVersion": "v74", + "GodepVersion": "v58", "Deps": [ { "ImportPath": "github.com/Sirupsen/logrus", @@ -52,18 +52,18 @@ }, { "ImportPath": "mynewt.apache.org/newt/util", - "Comment": "mynewt_0_9_0_rc3_tag-91-g904f79b", - "Rev": "904f79b15feeefe76a9e4ecc139c56fd54aa4412" + "Comment": "mynewt_0_9_0_tag-139-g8dddcf6", + "Rev": "8dddcf664861e0904e4c89b2bb4c2d498d4cb3a2" }, { "ImportPath": "mynewt.apache.org/newt/viper", - "Comment": "mynewt_0_9_0_rc3_tag-91-g904f79b", - "Rev": "904f79b15feeefe76a9e4ecc139c56fd54aa4412" + "Comment": "mynewt_0_9_0_tag-139-g8dddcf6", + "Rev": "8dddcf664861e0904e4c89b2bb4c2d498d4cb3a2" }, { "ImportPath": "mynewt.apache.org/newt/yaml", - "Comment": "mynewt_0_9_0_rc3_tag-91-g904f79b", - "Rev": "904f79b15feeefe76a9e4ecc139c56fd54aa4412" + "Comment": "mynewt_0_9_0_tag-139-g8dddcf6", + "Rev": "8dddcf664861e0904e4c89b2bb4c2d498d4cb3a2" } ] } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/builder/build.go ---------------------------------------------------------------------- diff --git a/newt/builder/build.go b/newt/builder/build.go index b8cbd39..17b64d1 100644 --- a/newt/builder/build.go +++ b/newt/builder/build.go @@ -29,7 +29,10 @@ import ( log "github.com/Sirupsen/logrus" "mynewt.apache.org/newt/newt/pkg" + "mynewt.apache.org/newt/newt/project" "mynewt.apache.org/newt/newt/symbol" + "mynewt.apache.org/newt/newt/syscfg" + "mynewt.apache.org/newt/newt/sysinit" "mynewt.apache.org/newt/newt/target" "mynewt.apache.org/newt/newt/toolchain" "mynewt.apache.org/newt/util" @@ -37,58 +40,31 @@ import ( type Builder struct { Packages map[*pkg.LocalPackage]*BuildPackage - features map[string]bool apis map[string]*BuildPackage appPkg *BuildPackage BspPkg *pkg.LocalPackage compilerInfo *toolchain.CompilerInfo - featureWhiteList []map[string]interface{} - featureBlackList []map[string]interface{} target *TargetBuilder linkerScript string buildName string LinkElf string -} - -func NewBuilder(t *TargetBuilder, buildName string) (*Builder, error) { - b := &Builder{} - - b.buildName = buildName - /* TODO */ - b.Init(t) - - return b, nil -} + injectedSettings map[string]string -func (b *Builder) Init(t *TargetBuilder) error { - - b.target = t - b.Packages = map[*pkg.LocalPackage]*BuildPackage{} - b.features = map[string]bool{} - b.apis = map[string]*BuildPackage{} - b.LinkElf = "" - - return nil + Cfg syscfg.Cfg } -func (b *Builder) AllFeatures() map[string]bool { - return b.features -} - -func (b *Builder) Features(pkg pkg.Package) map[string]bool { - featureList := map[string]bool{} - - for fname, _ := range b.features { - if b.CheckValidFeature(pkg, fname) { - featureList[fname] = true - } +func NewBuilder(t *TargetBuilder, buildName string) (*Builder, error) { + b := &Builder{ + Packages: map[*pkg.LocalPackage]*BuildPackage{}, + buildName: buildName, + apis: map[string]*BuildPackage{}, + LinkElf: "", + target: t, + injectedSettings: map[string]string{}, + Cfg: syscfg.Cfg{}, } - return featureList -} - -func (b *Builder) AddFeature(feature string) { - b.features[feature] = true + return b, nil } func (b *Builder) AddPackage(npkg *pkg.LocalPackage) *BuildPackage { @@ -122,29 +98,56 @@ func (b *Builder) AddApi(apiString string, bpkg *BuildPackage) bool { } } -func (b *Builder) loadDeps() error { - // Circularly resolve dependencies, identities, APIs, and required APIs - // until no new ones exist. +func (b *Builder) ApiNames() []string { + apiNames := make([]string, len(b.apis), len(b.apis)) + + i := 0 + for api, _ := range b.apis { + apiNames[i] = api + i += 1 + } + + return apiNames +} + +// @return changed,err +func (b *Builder) reloadCfg() (bool, error) { + apis := make([]string, len(b.apis)) + i := 0 + for api, _ := range b.apis { + apis[i] = api + i++ + } + + cfg, err := syscfg.Read(b.sortedLocalPackages(), apis, b.injectedSettings) + if err != nil { + return false, err + } + + changed := false + for k, v := range cfg { + oldval, ok := b.Cfg[k] + if !ok || len(oldval.History) != len(v.History) { + b.Cfg = cfg + changed = true + } + } + + return changed, nil +} + +func (b *Builder) loadDepsOnce() (bool, error) { + // Circularly resolve dependencies, APIs, and required APIs until no new + // ones exist. + newDeps := false for { reprocess := false for _, bpkg := range b.Packages { - newDeps, newFeatures, err := bpkg.Resolve(b) + newDeps, err := bpkg.Resolve(b, b.Cfg) if err != nil { - return err + return false, err } - if newFeatures { - // A new supported feature was discovered. It is impossible - // to determine what new dependency and API requirements are - // generated as a result. All packages need to be - // reprocessed. - for _, bpkg := range b.Packages { - bpkg.depsResolved = false - bpkg.apisSatisfied = false - } - reprocess = true - break - } if newDeps { // The new dependencies need to be processed. Iterate again // after this iteration completes. @@ -157,6 +160,43 @@ func (b *Builder) loadDeps() error { } } + return newDeps, nil +} + +func (b *Builder) loadDeps() error { + if _, err := b.loadDepsOnce(); err != nil { + return err + } + + for { + cfgChanged, err := b.reloadCfg() + if err != nil { + return err + } + if cfgChanged { + // A new supported feature was discovered. It is impossible + // to determine what new dependency and API requirements are + // generated as a result. All packages need to be + // reprocessed. + for _, bpkg := range b.Packages { + bpkg.depsResolved = false + bpkg.apisSatisfied = false + } + } + + newDeps, err := b.loadDepsOnce() + if err != nil { + return err + } + + if !newDeps && !cfgChanged { + break + } + } + + // Log the final syscfg. + syscfg.Log(b.Cfg) + return nil } @@ -233,12 +273,6 @@ func (b *Builder) newCompiler(bpkg *BuildPackage, c.AddInfo(ci) } - // Specify all the source yml files as dependencies. If a yml file has - // changed, a full rebuild is required. - for _, bp := range b.Packages { - c.AddDeps(bp.CfgFilenames()...) - } - return c, nil } @@ -271,25 +305,10 @@ func (b *Builder) buildPackage(bpkg *BuildPackage) error { srcDirs = append(srcDirs, srcDir) } - // Build the package source in two phases: - // 1. Non-test code. - // 2. Test code (if the "test" feature is enabled). - // - // This is done in two passes because the structure of - // architecture-specific directories is different for normal code and test - // code, and not easy to generalize into a single operation: - // * src/arch/<target-arch> - // * src/test/arch/<target-arch> for _, dir := range srcDirs { - if err = buildDir(dir, c, b.target.Bsp.Arch, []string{"test"}); err != nil { + if err = buildDir(dir, c, b.target.Bsp.Arch, nil); err != nil { return err } - if b.features["TEST"] { - testSrcDir := dir + "/test" - if err = buildDir(testSrcDir, c, b.target.Bsp.Arch, nil); err != nil { - return err - } - } } // Create a static library ("archive"). @@ -347,7 +366,7 @@ func (b *Builder) link(elfName string, linkerScript string, } if linkerScript != "" { - c.LinkerScript = b.target.Bsp.BasePath() + linkerScript + c.LinkerScript = b.target.Bsp.BasePath() + "/" + linkerScript } err = c.CompileElf(elfName, pkgNames, keepSymbols, b.LinkElf) if err != nil { @@ -363,9 +382,6 @@ func (b *Builder) link(elfName string, linkerScript string, func (b *Builder) PrepBuild(appPkg *pkg.LocalPackage, bspPkg *pkg.LocalPackage, targetPkg *pkg.LocalPackage) error { - b.featureBlackList = []map[string]interface{}{} - b.featureWhiteList = []map[string]interface{}{} - // Seed the builder with the app (if present), bsp, and target packages. b.BspPkg = bspPkg @@ -377,9 +393,6 @@ func (b *Builder) PrepBuild(appPkg *pkg.LocalPackage, appBpkg = b.AddPackage(appPkg) } b.appPkg = appBpkg - - b.featureBlackList = append(b.featureBlackList, appBpkg.FeatureBlackList()) - b.featureWhiteList = append(b.featureWhiteList, appBpkg.FeatureWhiteList()) } bspBpkg := b.Packages[bspPkg] @@ -388,14 +401,8 @@ func (b *Builder) PrepBuild(appPkg *pkg.LocalPackage, bspBpkg = b.AddPackage(bspPkg) } - b.featureBlackList = append(b.featureBlackList, bspPkg.FeatureBlackList()) - b.featureWhiteList = append(b.featureWhiteList, bspPkg.FeatureWhiteList()) - targetBpkg := b.AddPackage(targetPkg) - b.featureBlackList = append(b.featureBlackList, targetBpkg.FeatureBlackList()) - b.featureWhiteList = append(b.featureWhiteList, targetBpkg.FeatureWhiteList()) - // Populate the full set of packages to be built and resolve the feature // set. if err := b.loadDeps(); err != nil { @@ -428,12 +435,12 @@ func (b *Builder) PrepBuild(appPkg *pkg.LocalPackage, baseCi := toolchain.NewCompilerInfo() // Target flags. - log.Debugf("Generating build flags for target %s", b.target.target.FullName()) + log.Debugf("Generating build flags for target %s", + b.target.target.FullName()) targetCi, err := targetBpkg.CompilerInfo(b) if err != nil { return err } - baseCi.AddCompilerInfo(targetCi) // App flags. @@ -443,6 +450,7 @@ func (b *Builder) PrepBuild(appPkg *pkg.LocalPackage, if err != nil { return err } + baseCi.AddCompilerInfo(appCi) } @@ -468,6 +476,18 @@ func (b *Builder) PrepBuild(appPkg *pkg.LocalPackage, // package being built are calculated. b.compilerInfo = baseCi + lpkgs := b.sortedLocalPackages() + if err := syscfg.EnsureWritten(b.Cfg, lpkgs, b.ApiNames(), + targetPkg.BasePath()); err != nil { + return err + } + + if err := sysinit.EnsureWritten(lpkgs, targetPkg.BasePath()); err != nil { + return err + } + + b.compilerInfo = baseCi + return nil } @@ -493,29 +513,11 @@ func (b *Builder) matchFeature(flist []map[string]interface{}, return false } -func (b *Builder) CheckValidFeature(pkg pkg.Package, - feature string) bool { - - // If the feature is not in the blacklist, automatically valid - if match := b.matchFeature(b.featureBlackList, pkg, feature); !match { - return true - } - - // If it is in the blacklist, check if its in the whitelist - // if not, override the feature definition. - if match := b.matchFeature(b.featureWhiteList, pkg, feature); match { - return true - } else { - return false - } -} - func (b *Builder) AddCompilerInfo(info *toolchain.CompilerInfo) { b.compilerInfo.AddCompilerInfo(info) } func (b *Builder) Build() error { - // Build the packages alphabetically to ensure a consistent order. bpkgs := b.sortedBuildPackages() for _, bpkg := range bpkgs { @@ -555,32 +557,50 @@ func (b *Builder) TestLink(linkerScript string) error { return nil } -func (b *Builder) Test(p *pkg.LocalPackage) error { +func (b *Builder) pkgWithPath(path string) *BuildPackage { + for _, p := range b.Packages { + if p.BasePath() == path { + return p + } + } - // Seed the builder with the package under test. - testBpkg := b.AddPackage(p) + return nil +} - // Define the PKG_TEST symbol while the package under test is being - // compiled. This symbol enables the appropriate main function that - // usually comes from an app. - testPkgCi, err := testBpkg.CompilerInfo(b) - if err != nil { - return err +func (b *Builder) testOwner(p *BuildPackage) *BuildPackage { + if p.Type() != pkg.PACKAGE_TYPE_UNITTEST { + panic("Expected unittest package; got: " + p.Name()) } - testPkgCi.Cflags = append(testPkgCi.Cflags, "-DMYNEWT_SELFTEST") + curPath := p.BasePath() + + for { + parentPath := filepath.Dir(curPath) + if parentPath == project.GetProject().BasePath || parentPath == "." { + return nil + } + + parentPkg := b.pkgWithPath(parentPath) + if parentPkg != nil && parentPkg.Type() != pkg.PACKAGE_TYPE_UNITTEST { + log.Debugf("OWNER=%s", parentPkg.Name()) + return parentPkg + } + + curPath = parentPath + } +} + +func (b *Builder) Test(p *pkg.LocalPackage) error { // Build the packages alphabetically to ensure a consistent order. bpkgs := b.sortedBuildPackages() for _, bpkg := range bpkgs { - err = b.buildPackage(bpkg) - if err != nil { + if err := b.buildPackage(bpkg); err != nil { return err } } testFilename := b.TestExePath(p.Name()) - err = b.link(testFilename, "", nil) - if err != nil { + if err := b.link(testFilename, "", nil); err != nil { return err } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/builder/buildpackage.go ---------------------------------------------------------------------- diff --git a/newt/builder/buildpackage.go b/newt/builder/buildpackage.go index b2d59fe..2cdd75b 100644 --- a/newt/builder/buildpackage.go +++ b/newt/builder/buildpackage.go @@ -30,6 +30,7 @@ import ( "mynewt.apache.org/newt/newt/newtutil" "mynewt.apache.org/newt/newt/pkg" "mynewt.apache.org/newt/newt/project" + "mynewt.apache.org/newt/newt/syscfg" "mynewt.apache.org/newt/newt/toolchain" "mynewt.apache.org/newt/util" ) @@ -139,20 +140,21 @@ func (bpkg *BuildPackage) CompilerInfo(b *Builder) (*toolchain.CompilerInfo, err } ci := toolchain.NewCompilerInfo() - ci.Cflags = newtutil.GetStringSliceFeatures(bpkg.Viper, b.Features(bpkg), + features := syscfg.FeaturesForLpkg(b.Cfg, bpkg.LocalPackage) + ci.Cflags = newtutil.GetStringSliceFeatures(bpkg.Viper, features, "pkg.cflags") - ci.Lflags = newtutil.GetStringSliceFeatures(bpkg.Viper, b.Features(bpkg), + ci.Lflags = newtutil.GetStringSliceFeatures(bpkg.Viper, features, "pkg.lflags") - ci.Aflags = newtutil.GetStringSliceFeatures(bpkg.Viper, b.Features(bpkg), + ci.Aflags = newtutil.GetStringSliceFeatures(bpkg.Viper, features, "pkg.aflags") - for fname, _ := range b.Features(bpkg) { - ci.Cflags = append(ci.Cflags, fmt.Sprintf("-DFEATURE_%s", fname)) + for k, _ := range bpkg.InjectedSettings() { + ci.Cflags = append(ci.Cflags, syscfg.FeatureToCflag(k)) } ci.IgnoreFiles = []*regexp.Regexp{} ignPats := newtutil.GetStringSliceFeatures(bpkg.Viper, - b.Features(bpkg), "pkg.ign_files") + features, "pkg.ign_files") for _, str := range ignPats { re, err := regexp.Compile(str) if err != nil { @@ -164,7 +166,7 @@ func (bpkg *BuildPackage) CompilerInfo(b *Builder) (*toolchain.CompilerInfo, err ci.IgnoreDirs = []*regexp.Regexp{} ignPats = newtutil.GetStringSliceFeatures(bpkg.Viper, - b.Features(bpkg), "pkg.ign_dirs") + features, "pkg.ign_dirs") for _, str := range ignPats { re, err := regexp.Compile(str) if err != nil { @@ -175,38 +177,19 @@ func (bpkg *BuildPackage) CompilerInfo(b *Builder) (*toolchain.CompilerInfo, err } bpkg.SourceDirectories = newtutil.GetStringSliceFeatures(bpkg.Viper, - b.Features(bpkg), "pkg.src_dirs") + features, "pkg.src_dirs") includePaths, err := bpkg.recursiveIncludePaths(b) if err != nil { return nil, err } + ci.Includes = append(bpkg.privateIncludeDirs(b), includePaths...) bpkg.ci = ci return bpkg.ci, nil } -func (bpkg *BuildPackage) loadFeatures(b *Builder) (map[string]bool, bool) { - features := b.AllFeatures() - - foundNewFeature := false - - newFeatures := newtutil.GetStringSliceFeatures(bpkg.Viper, features, - "pkg.features") - for _, nfeature := range newFeatures { - _, ok := features[nfeature] - if !ok { - b.AddFeature(nfeature) - foundNewFeature = true - log.Debugf("Detected new feature: %s (%s)", nfeature, - bpkg.Name()) - } - } - - return b.Features(bpkg), foundNewFeature -} - // Searches for a package which can satisfy bpkg's API requirement. If such a // package is found, bpkg's API requirement is marked as satisfied, and the // package is added to bpkg's dependency list. @@ -270,8 +253,7 @@ func (bpkg *BuildPackage) loadDeps(b *Builder, // Determine if this package supports any APIs that we haven't seen // yet. If so, another full iteration is required. - apis := newtutil.GetStringSliceFeatures(bpkg.Viper, b.Features(bpkg), - "pkg.apis") + apis := newtutil.GetStringSliceFeatures(bpkg.Viper, features, "pkg.apis") for _, api := range apis { newApi := b.AddApi(api, bpkg) if newApi { @@ -285,7 +267,9 @@ func (bpkg *BuildPackage) loadDeps(b *Builder, // @return bool true if a new dependency was detected as a // result of satisfying an API for this // package. -func (bpkg *BuildPackage) satisfyApis(b *Builder) bool { +func (bpkg *BuildPackage) satisfyApis(b *Builder, + features map[string]bool) bool { + // Assume all this package's APIs are satisfied and that no new // dependencies will be detected. bpkg.apisSatisfied = true @@ -293,7 +277,7 @@ func (bpkg *BuildPackage) satisfyApis(b *Builder) bool { // Determine if any of the package's API requirements can now be satisfied. // If so, another full iteration is required. - reqApis := newtutil.GetStringSliceFeatures(bpkg.Viper, b.Features(bpkg), + reqApis := newtutil.GetStringSliceFeatures(bpkg.Viper, features, "pkg.req_apis") for _, reqApi := range reqApis { reqStatus, ok := bpkg.reqApiMap[reqApi] @@ -364,19 +348,25 @@ func (bpkg *BuildPackage) privateIncludeDirs(b *Builder) []string { incls = append(incls, srcDir) incls = append(incls, srcDir+"/arch/"+b.target.Bsp.Arch) - if b.Features(bpkg)["TEST"] { - testSrcDir := srcDir + "/test" - incls = append(incls, testSrcDir) - incls = append(incls, testSrcDir+"/arch/"+b.target.Bsp.Arch) - } - - // If pkgType == SDK, include all the items in "ext" directly into the - // include path - if bpkg.Type() == pkg.PACKAGE_TYPE_SDK { + switch bpkg.Type() { + case pkg.PACKAGE_TYPE_SDK: + // If pkgType == SDK, include all the items in "ext" directly into the + // include path incls = append(incls, b.target.Bsp.BasePath()+"/include/bsp/") sdkIncls := bpkg.findSdkIncludes() incls = append(incls, sdkIncls...) + + case pkg.PACKAGE_TYPE_UNITTEST: + // A unittest package gets access to its parent package's private + // includes. + parentPkg := b.testOwner(bpkg) + if parentPkg != nil { + parentIncls := parentPkg.privateIncludeDirs(b) + incls = append(incls, parentIncls...) + } + + default: } return incls @@ -396,42 +386,38 @@ func (bpkg *BuildPackage) privateIncludeDirs(b *Builder) []string { // // @return bool true if >=1 dependencies were resolved // bool true if >=1 new features were detected -func (bpkg *BuildPackage) Resolve(b *Builder) (bool, bool, error) { +func (bpkg *BuildPackage) Resolve(b *Builder, + cfg syscfg.Cfg) (bool, error) { + var err error newDeps := false - newFeatures := false - if !bpkg.depsResolved { - var features map[string]bool + features := syscfg.FeaturesForLpkg(cfg, bpkg.LocalPackage) - features, newFeatures = bpkg.loadFeatures(b) + if !bpkg.depsResolved { newDeps, err = bpkg.loadDeps(b, features) if err != nil { - return false, false, err + return false, err } - bpkg.depsResolved = !newFeatures && !newDeps - + bpkg.depsResolved = !newDeps } if !bpkg.apisSatisfied { - newApiDep := bpkg.satisfyApis(b) + newApiDep := bpkg.satisfyApis(b, features) if newApiDep { newDeps = true } } - return newDeps, newFeatures, nil -} - -func (bp *BuildPackage) Init(pkg *pkg.LocalPackage) { - bp.LocalPackage = pkg - bp.reqApiMap = map[string]reqApiStatus{} + return newDeps, nil } func NewBuildPackage(pkg *pkg.LocalPackage) *BuildPackage { - bpkg := &BuildPackage{} - bpkg.Init(pkg) + bpkg := &BuildPackage{ + LocalPackage: pkg, + reqApiMap: map[string]reqApiStatus{}, + } return bpkg } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/builder/buildutil.go ---------------------------------------------------------------------- diff --git a/newt/builder/buildutil.go b/newt/builder/buildutil.go index ca5a157..f35a1db 100644 --- a/newt/builder/buildutil.go +++ b/newt/builder/buildutil.go @@ -23,10 +23,13 @@ import ( "bytes" "path/filepath" "sort" + "strings" log "github.com/Sirupsen/logrus" + "mynewt.apache.org/newt/newt/pkg" "mynewt.apache.org/newt/newt/project" + "mynewt.apache.org/newt/newt/syscfg" "mynewt.apache.org/newt/util" ) @@ -77,25 +80,27 @@ func (b *Builder) AppBinBasePath() string { return b.PkgBinDir(pkgName) + "/" + filepath.Base(pkgName) } +func TestTargetName(testPkgName string) string { + return strings.Replace(testPkgName, "/", "_", -1) +} + func (b *Builder) TestExePath(pkgName string) string { - return b.PkgBinDir(pkgName) + "/test_" + filepath.Base(pkgName) + return b.PkgBinDir(pkgName) + "/" + TestTargetName(pkgName) } func (b *Builder) FeatureString() string { var buffer bytes.Buffer - features := make([]string, 0, len(b.Features(nil))) - for f, _ := range b.Features(nil) { - features = append(features, f) + featureMap := syscfg.Features(b.Cfg) + featureSlice := make([]string, 0, len(featureMap)) + for k, _ := range featureMap { + featureSlice = append(featureSlice, k) } - sort.Strings(features) + sort.Strings(featureSlice) - first := true - for _, feature := range features { - if !first { + for i, feature := range featureSlice { + if i != 0 { buffer.WriteString(" ") - } else { - first = false } buffer.WriteString(feature) @@ -168,6 +173,17 @@ func (b *Builder) sortedBuildPackages() []*BuildPackage { return sorter.bpkgs } +func (b *Builder) sortedLocalPackages() []*pkg.LocalPackage { + bpkgs := b.sortedBuildPackages() + + lpkgs := make([]*pkg.LocalPackage, len(bpkgs), len(bpkgs)) + for i, bpkg := range bpkgs { + lpkgs[i] = bpkg.LocalPackage + } + + return lpkgs +} + func (b *Builder) logDepInfo() { // Log feature set. log.Debugf("Feature set: [" + b.FeatureString() + "]") http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/builder/load.go ---------------------------------------------------------------------- diff --git a/newt/builder/load.go b/newt/builder/load.go index 0c1a85b..9596532 100644 --- a/newt/builder/load.go +++ b/newt/builder/load.go @@ -25,6 +25,7 @@ import ( "path/filepath" "mynewt.apache.org/newt/newt/project" + "mynewt.apache.org/newt/newt/syscfg" "mynewt.apache.org/newt/util" ) @@ -87,7 +88,7 @@ func (b *Builder) Load(image_slot int, extraJtagCmd string) error { downloadCmd := fmt.Sprintf("%s %s %s %s", envSettings, downloadScript, bspPath, binBaseName) - features := b.Features(nil) + features := syscfg.Features(b.Cfg) if _, ok := features["bootloader"]; ok { util.StatusMessage(util.VERBOSITY_DEFAULT, http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/builder/targetbuild.go ---------------------------------------------------------------------- diff --git a/newt/builder/targetbuild.go b/newt/builder/targetbuild.go index 3d9d96b..96b43f0 100644 --- a/newt/builder/targetbuild.go +++ b/newt/builder/targetbuild.go @@ -27,6 +27,7 @@ import ( "mynewt.apache.org/newt/newt/pkg" "mynewt.apache.org/newt/newt/project" "mynewt.apache.org/newt/newt/symbol" + "mynewt.apache.org/newt/newt/syscfg" "mynewt.apache.org/newt/newt/target" "mynewt.apache.org/newt/newt/toolchain" "mynewt.apache.org/newt/util" @@ -156,7 +157,7 @@ func (t *TargetBuilder) Build() error { /* Build the Apps */ project.ResetDeps(t.AppList) - if err := t.Bsp.Reload(t.App.Features(t.App.BspPkg)); err != nil { + if err := t.Bsp.Reload(syscfg.Features(t.App.Cfg)); err != nil { return err } @@ -181,7 +182,7 @@ func (t *TargetBuilder) Build() error { /* rebuild the loader */ project.ResetDeps(t.LoaderList) - if err = t.Bsp.Reload(t.Loader.Features(t.Loader.BspPkg)); err != nil { + if err = t.Bsp.Reload(syscfg.Features(t.Loader.Cfg)); err != nil { return err } @@ -403,10 +404,11 @@ func (t *TargetBuilder) Test(p *pkg.LocalPackage) error { // used: // * TEST: ensures that the test code gets compiled. // * SELFTEST: indicates that there is no app. - t.App.AddFeature("TEST") - t.App.AddFeature("SELFTEST") + t.App.injectedSettings["TEST"] = "1" + p.InjectedSettings()["SELFTEST"] = "1" - err = t.App.PrepBuild(p, bspPkg, targetPkg) + t.App.AddPackage(p) + err = t.App.PrepBuild(nil, bspPkg, targetPkg) if err != nil { return err http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/cli/build_cmds.go ---------------------------------------------------------------------- diff --git a/newt/cli/build_cmds.go b/newt/cli/build_cmds.go index bc19cf5..a26deb7 100644 --- a/newt/cli/build_cmds.go +++ b/newt/cli/build_cmds.go @@ -22,6 +22,7 @@ package cli import ( "fmt" "os" + "path/filepath" "github.com/spf13/cobra" "mynewt.apache.org/newt/newt/builder" @@ -33,12 +34,68 @@ import ( const TARGET_TEST_NAME = "unittest" -var extraJtagCmd string +var testablePkgMap map[*pkg.LocalPackage]struct{} + +func testablePkgs() map[*pkg.LocalPackage]struct{} { + if testablePkgMap != nil { + return testablePkgMap + } + + testablePkgMap := map[*pkg.LocalPackage]struct{}{} + + // Create a map of path => lclPkg. + proj := project.GetProject() + allPkgs := proj.PackagesOfType(-1) + pathLpkgMap := make(map[string]*pkg.LocalPackage, len(allPkgs)) + for _, p := range allPkgs { + lpkg := p.(*pkg.LocalPackage) + pathLpkgMap[lpkg.BasePath()] = lpkg + } + + // Add all unit test packages to the testable package map. + testPkgs := proj.PackagesOfType(pkg.PACKAGE_TYPE_UNITTEST) + for _, p := range testPkgs { + lclPack := p.(*pkg.LocalPackage) + testablePkgMap[lclPack] = struct{}{} + } + + // Next add first ancestor of each test package. + for testPkg, _ := range testablePkgMap { + for cur := filepath.Dir(testPkg.BasePath()); cur != proj.BasePath; cur = filepath.Dir(cur) { + lpkg := pathLpkgMap[cur] + if lpkg != nil && lpkg.Type() != pkg.PACKAGE_TYPE_UNITTEST { + testablePkgMap[lpkg] = struct{}{} + break + } + } + } -func pkgIsTestable(pack *pkg.LocalPackage) bool { - return util.NodeExist(pack.BasePath() + "/src/test") + return testablePkgMap } +func pkgToUnitTests(pack *pkg.LocalPackage) []*pkg.LocalPackage { + // If the user specified a unittest package, just test that one. + if pack.Type() == pkg.PACKAGE_TYPE_UNITTEST { + return []*pkg.LocalPackage{pack} + } + + // Otherwise, return all the package's direct descendants that are unit + // test packages. + result := []*pkg.LocalPackage{} + srcPath := pack.BasePath() + for p, _ := range testablePkgs() { + if p.Type() == pkg.PACKAGE_TYPE_UNITTEST && + filepath.Dir(p.BasePath()) == srcPath { + + result = append(result, p) + } + } + + return result +} + +var extraJtagCmd string + func buildRunCmd(cmd *cobra.Command, args []string) { if err := project.Initialize(); err != nil { NewtUsage(cmd, err) @@ -132,10 +189,17 @@ func cleanRunCmd(cmd *cobra.Command, args []string) { } } -func testRunCmd(cmd *cobra.Command, args []string) { - if err := project.Initialize(); err != nil { - NewtUsage(cmd, err) +func pkgnames(pkgs []*pkg.LocalPackage) string { + s := "" + + for _, p := range pkgs { + s += p.Name() + " " } + + return s +} + +func testRunCmd(cmd *cobra.Command, args []string) { if len(args) < 1 { NewtUsage(cmd, nil) } @@ -152,26 +216,26 @@ func testRunCmd(cmd *cobra.Command, args []string) { NewtUsage(cmd, err) } - if !pkgIsTestable(pack) { + testPkgs := pkgToUnitTests(pack) + if len(testPkgs) == 0 { NewtUsage(nil, util.FmtNewtError("Package %s contains no "+ "unit tests", pack.FullName())) } - packs = append(packs, pack) + packs = append(packs, testPkgs...) } } + proj := project.GetProject() + if testAll { - packs = []*pkg.LocalPackage{} - for _, repoHash := range project.GetProject().PackageList() { - for _, pack := range *repoHash { - lclPack := pack.(*pkg.LocalPackage) - - if pkgIsTestable(lclPack) { - packs = append(packs, lclPack) - } - } + packItfs := proj.PackagesOfType(pkg.PACKAGE_TYPE_UNITTEST) + packs = make([]*pkg.LocalPackage, len(packItfs)) + for i, p := range packItfs { + packs[i] = p.(*pkg.LocalPackage) } + + packs = pkg.SortLclPkgs(packs) } if len(packs) == 0 { @@ -186,13 +250,36 @@ func testRunCmd(cmd *cobra.Command, args []string) { NewtUsage(nil, err) } - // Use the standard unit test target for all tests. - t := ResolveTarget(TARGET_TEST_NAME) - if t == nil { + // Each unit test package gets its own target. This target is a copy + // of the base unit test package, just with an appropriate name. The + // reason each test needs a unique target is: syscfg and sysinit are + // target-specific. If each test package shares a target, they will + // overwrite these generated headers each time they are run. Worse, if + // two tests are run back-to-back, the timestamps may indicate that the + // headers have not changed between tests, causing build failures. + baseTarget := ResolveTarget(TARGET_TEST_NAME) + if baseTarget == nil { NewtUsage(nil, util.NewNewtError("Can't find unit test target: "+ TARGET_TEST_NAME)) } + targetName := fmt.Sprintf("%s/%s/%s", + TARGET_DEFAULT_DIR, TARGET_TEST_NAME, + builder.TestTargetName(pack.Name())) + + t := ResolveTarget(targetName) + if t == nil { + targetName, err := ResolveNewTargetName(targetName) + if err != nil { + NewtUsage(nil, err) + } + + t = baseTarget.Clone(proj.LocalRepo(), targetName) + if err := t.Save(); err != nil { + NewtUsage(nil, err) + } + } + b, err := builder.NewTargetBuilder(t) if err != nil { NewtUsage(nil, err) http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/cli/complete_cmd.go ---------------------------------------------------------------------- diff --git a/newt/cli/complete_cmd.go b/newt/cli/complete_cmd.go index c01410c..b2e83b6 100644 --- a/newt/cli/complete_cmd.go +++ b/newt/cli/complete_cmd.go @@ -54,35 +54,17 @@ func targetList() []string { return targetNames } -/* return a list of all packages */ +/* @return A slice of all testable package names. */ func packageList() []string { - - err := project.Initialize() - - var list []string - - if err != nil { - return list - } - for _, repoHash := range project.GetProject().PackageList() { - for _, pack := range *repoHash { - lclPack := pack.(*pkg.LocalPackage) - - if pkgIsTestable(lclPack) { - list = append(list, lclPack.FullName()) - } + packs := testablePkgs() + names := make([]string, 0, len(packs)) + for pack, _ := range packs { + if pack.Type() != pkg.PACKAGE_TYPE_UNITTEST { + names = append(names, pack.FullName()) } } - return list -} -func isValueInList(value string, list []string) int { - for i, v := range list { - if v == value { - return i - } - } - return -1 + return names } func completeRunCmd(cmd *cobra.Command, args []string) { http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/cli/target_cmds.go ---------------------------------------------------------------------- diff --git a/newt/cli/target_cmds.go b/newt/cli/target_cmds.go index b9ebada..364fbaf 100644 --- a/newt/cli/target_cmds.go +++ b/newt/cli/target_cmds.go @@ -29,8 +29,10 @@ import ( "strings" "github.com/spf13/cobra" + "mynewt.apache.org/newt/newt/builder" "mynewt.apache.org/newt/newt/pkg" "mynewt.apache.org/newt/newt/project" + "mynewt.apache.org/newt/newt/syscfg" "mynewt.apache.org/newt/newt/target" "mynewt.apache.org/newt/util" ) @@ -333,6 +335,90 @@ func targetCopyCmd(cmd *cobra.Command, args []string) { } } +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) + + unfixed := syscfg.UnfixedValue(entry) + if unfixed != entry.Value { + util.StatusMessage(util.VERBOSITY_DEFAULT, " [%s]", unfixed) + } + util.StatusMessage(util.VERBOSITY_DEFAULT, "\n") + + if len(entry.History) > 1 { + util.StatusMessage(util.VERBOSITY_DEFAULT, + " * Overridden: ") + for i := 1; i < len(entry.History); i++ { + util.StatusMessage(util.VERBOSITY_DEFAULT, "%s, ", + entry.History[i].Source.Name()) + } + util.StatusMessage(util.VERBOSITY_DEFAULT, + "default=%s\n", entry.History[0].Value) + } +} + +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[name]) + } +} + +func printCfg(cfg syscfg.Cfg) { + 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 targetConfigCmd(cmd *cobra.Command, args []string) { + if err := project.Initialize(); err != nil { + NewtUsage(cmd, err) + } + if len(args) != 1 { + NewtUsage(cmd, util.NewNewtError("Must specify target name")) + } + + t, err := resolveExistingTargetArg(args[0]) + if err != nil { + NewtUsage(cmd, err) + } + + b, err := builder.NewTargetBuilder(t) + if err != nil { + NewtUsage(nil, err) + } + + if err := b.PrepBuild(); err != nil { + NewtUsage(nil, err) + } + + printCfg(b.App.Cfg) +} + func AddTargetCommands(cmd *cobra.Command) { targetHelpText := "" targetHelpEx := "" @@ -415,12 +501,25 @@ func AddTargetCommands(cmd *cobra.Command) { copyHelpEx += " newt target copy blinky_sim my_target" copyCmd := &cobra.Command{ - Use: "copy", - Short: "Copy target", - Long: copyHelpText, - Example: copyHelpEx, - Run: targetCopyCmd, + Use: "copy", + Short: "Copy target", + Long: copyHelpText, + Example: copyHelpEx, + Run: targetCopyCmd, + ValidArgs: targetList(), } targetCmd.AddCommand(copyCmd) + + configHelpText := "View a target's system configuration." + + configCmd := &cobra.Command{ + Use: "config <target-name>", + Short: "View target system configuration", + Long: configHelpText, + Run: targetConfigCmd, + ValidArgs: targetList(), + } + + targetCmd.AddCommand(configCmd) } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/newt.go ---------------------------------------------------------------------- diff --git a/newt/newt.go b/newt/newt.go index 03fb8de..f1e0c2d 100644 --- a/newt/newt.go +++ b/newt/newt.go @@ -28,6 +28,7 @@ import ( "mynewt.apache.org/newt/newt/cli" "mynewt.apache.org/newt/newt/newtutil" + "mynewt.apache.org/newt/newt/project" "mynewt.apache.org/newt/util" ) @@ -114,13 +115,14 @@ func newtCmd() *cobra.Command { } func main() { - cmd := newtCmd() /* some of the setup code logs which messes with autocomplete */ hold_lvl := log.GetLevel() log.SetLevel(log.FatalLevel) + initErr := project.Initialize() + cli.AddCompleteCommands(cmd) cli.AddProjectCommands(cmd) cli.AddTargetCommands(cmd) @@ -146,6 +148,10 @@ func main() { cmd.SilenceUsage = false } + if initErr != nil { + cli.NewtUsage(nil, initErr) + } + log.SetLevel(hold_lvl) cmd.Execute() } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/newtutil/newtutil.go ---------------------------------------------------------------------- diff --git a/newt/newtutil/newtutil.go b/newt/newtutil/newtutil.go index 42e68fb..947ab49 100644 --- a/newt/newtutil/newtutil.go +++ b/newt/newtutil/newtutil.go @@ -27,6 +27,8 @@ import ( "strconv" "strings" + "github.com/spf13/cast" + "mynewt.apache.org/newt/util" "mynewt.apache.org/newt/viper" ) @@ -34,6 +36,51 @@ import ( var NewtVersionStr string = "Apache Newt (incubating) version: 0.9.0" var NewtBlinkyTag string = "mynewt_0_9_0_tag" +func GetSliceFeatures(v *viper.Viper, features map[string]bool, + key string) []interface{} { + + val := v.Get(key) + vals := []interface{}{val} + + // Process the features in alphabetical order to ensure consistent + // results across repeated runs. + var featureKeys []string + for feature, _ := range features { + featureKeys = append(featureKeys, feature) + } + sort.Strings(featureKeys) + + for _, feature := range featureKeys { + overwriteVal := v.Get(key + "." + feature + ".OVERWRITE") + if overwriteVal != nil { + return []interface{}{overwriteVal} + } + + appendVal := v.Get(key + "." + feature) + if appendVal != nil { + vals = append(vals, appendVal) + } + } + + return vals +} + +func GetStringMapFeatures(v *viper.Viper, features map[string]bool, + key string) map[string]interface{} { + + result := map[string]interface{}{} + + slice := GetSliceFeatures(v, features, key) + for _, itf := range slice { + sub := cast.ToStringMap(itf) + for k, v := range sub { + result[k] = v + } + } + + return result +} + func GetStringFeatures(v *viper.Viper, features map[string]bool, key string) string { val := v.GetString(key) @@ -87,28 +134,15 @@ func GetBoolFeatures(v *viper.Viper, features map[string]bool, func GetStringSliceFeatures(v *viper.Viper, features map[string]bool, key string) []string { - val := v.GetStringSlice(key) + vals := GetSliceFeatures(v, features, key) - // string empty items - result := []string{} - for _, item := range val { - if item == "" || item == " " { - continue - } - result = append(result, item) + strVals := []string{} + for _, v := range vals { + subVals := cast.ToStringSlice(v) + strVals = append(strVals, subVals...) } - for item, _ := range features { - overwriteVal := v.GetStringSlice(key + "." + item + ".OVERWRITE") - if overwriteVal != nil { - result = overwriteVal - break - } - - result = append(result, v.GetStringSlice(key+"."+item)...) - } - - return result + return strVals } // Parses a string of the following form: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/pkg/localpackage.go ---------------------------------------------------------------------- diff --git a/newt/pkg/localpackage.go b/newt/pkg/localpackage.go index 0e73d8d..86c5777 100644 --- a/newt/pkg/localpackage.go +++ b/newt/pkg/localpackage.go @@ -60,15 +60,15 @@ type LocalPackage struct { desc *PackageDesc // Dependencies for this package deps []*Dependency - // APIs that this package exports - apis []string - // APIs that this package requires - reqApis []string - // This is only used for top-level packages, but make no distinction - // and always read it in. - featureBlackList map[string]interface{} - featureWhiteList map[string]interface{} + // Package init function name and stage. These are used to generate the + // sysinit C file. + initFnName string + initStage 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 // Pointer to pkg.yml configuration structure Viper *viper.Viper @@ -82,8 +82,10 @@ func NewLocalPackage(r *repo.Repo, pkgDir string) *LocalPackage { desc: &PackageDesc{}, // XXX: Initialize viper object; clients should not need to check for // nil pointer. + repo: r, + basePath: filepath.Clean(pkgDir) + "/", // XXX: Remove slash. + injectedSettings: map[string]string{}, } - pkg.Init(r, pkgDir) return pkg } @@ -101,7 +103,7 @@ func (pkg *LocalPackage) FullName() string { } func (pkg *LocalPackage) BasePath() string { - return pkg.basePath + return filepath.Clean(pkg.basePath) } func (pkg *LocalPackage) Type() interfaces.PackageType { @@ -201,22 +203,6 @@ func (pkg *LocalPackage) Deps() []*Dependency { return pkg.deps } -func (pkg *LocalPackage) AddApi(api string) { - pkg.apis = append(pkg.apis, api) -} - -func (pkg *LocalPackage) Apis() []string { - return pkg.apis -} - -func (pkg *LocalPackage) AddReqApi(api string) { - pkg.reqApis = append(pkg.reqApis, api) -} - -func (pkg *LocalPackage) ReqApis() []string { - return pkg.reqApis -} - func (pkg *LocalPackage) readDesc(v *viper.Viper) (*PackageDesc, error) { pdesc := &PackageDesc{} @@ -228,11 +214,6 @@ func (pkg *LocalPackage) readDesc(v *viper.Viper) (*PackageDesc, error) { return pdesc, nil } -func (pkg *LocalPackage) Init(repo *repo.Repo, pkgDir string) { - pkg.repo = repo - pkg.basePath = filepath.Clean(pkgDir) + "/" -} - func (pkg *LocalPackage) sequenceString(key string) string { var buffer bytes.Buffer @@ -314,8 +295,8 @@ func (pkg *LocalPackage) Load() error { } } - pkg.featureBlackList = v.GetStringMap("pkg.feature_blacklist") - pkg.featureWhiteList = v.GetStringMap("pkg.feature_whitelist") + pkg.initFnName = v.GetString("pkg.init_function") + pkg.initStage = v.GetInt("pkg.init_stage") // Read the package description from the file pkg.desc, err = pkg.readDesc(v) @@ -328,12 +309,16 @@ func (pkg *LocalPackage) Load() error { return nil } -func (pkg *LocalPackage) FeatureBlackList() map[string]interface{} { - return pkg.featureBlackList +func (pkg *LocalPackage) InitStage() int { + return pkg.initStage +} + +func (pkg *LocalPackage) InitFnName() string { + return pkg.initFnName } -func (pkg *LocalPackage) FeatureWhiteList() map[string]interface{} { - return pkg.featureWhiteList +func (pkg *LocalPackage) InjectedSettings() map[string]string { + return pkg.injectedSettings } func (pkg *LocalPackage) Clone(newRepo *repo.Repo, @@ -356,8 +341,7 @@ func (pkg *LocalPackage) Clone(newRepo *repo.Repo, } func LoadLocalPackage(repo *repo.Repo, pkgDir string) (*LocalPackage, error) { - pkg := &LocalPackage{} - pkg.Init(repo, pkgDir) + pkg := NewLocalPackage(repo, pkgDir) err := pkg.Load() return pkg, err } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/pkg/package.go ---------------------------------------------------------------------- diff --git a/newt/pkg/package.go b/newt/pkg/package.go index 4fa988c..644889e 100644 --- a/newt/pkg/package.go +++ b/newt/pkg/package.go @@ -1,5 +1,4 @@ /** - PACKAGE_TYPE_LIB: "lib", * 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 @@ -16,7 +15,7 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. -*/ + */ package pkg @@ -37,6 +36,7 @@ const ( PACKAGE_TYPE_COMPILER PACKAGE_TYPE_LIB PACKAGE_TYPE_TARGET + PACKAGE_TYPE_UNITTEST ) var PackageTypeNames = map[interfaces.PackageType]string{ @@ -46,6 +46,7 @@ var PackageTypeNames = map[interfaces.PackageType]string{ PACKAGE_TYPE_COMPILER: "compiler", PACKAGE_TYPE_LIB: "lib", PACKAGE_TYPE_TARGET: "target", + PACKAGE_TYPE_UNITTEST: "unittest", } // An interface, representing information about a Package http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/pkg/packageutil.go ---------------------------------------------------------------------- diff --git a/newt/pkg/packageutil.go b/newt/pkg/packageutil.go new file mode 100644 index 0000000..f3f6132 --- /dev/null +++ b/newt/pkg/packageutil.go @@ -0,0 +1,32 @@ +package pkg + +import ( + "sort" +) + +type lpkgSorter struct { + pkgs []*LocalPackage +} + +func (s lpkgSorter) Len() int { + return len(s.pkgs) +} +func (s lpkgSorter) Swap(i, j int) { + s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i] +} +func (s lpkgSorter) Less(i, j int) bool { + return s.pkgs[i].Name() < s.pkgs[j].Name() +} + +func SortLclPkgs(pkgs []*LocalPackage) []*LocalPackage { + sorter := lpkgSorter{ + pkgs: make([]*LocalPackage, 0, len(pkgs)), + } + + for _, p := range pkgs { + sorter.pkgs = append(sorter.pkgs, p) + } + + sort.Sort(sorter) + return sorter.pkgs +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/project/project.go ---------------------------------------------------------------------- diff --git a/newt/project/project.go b/newt/project/project.go index 78585af..29646e5 100644 --- a/newt/project/project.go +++ b/newt/project/project.go @@ -497,7 +497,6 @@ func findProjectDir(dir string) (string, error) { log.Debugf("Searching for project file %s", projFile) if util.NodeExist(projFile) { - log.Infof("Project file found at %s", projFile) break } @@ -518,7 +517,6 @@ func (proj *Project) loadPackageList() error { // packages / store them in the project package list. repos := proj.Repos() for name, repo := range repos { - log.Debugf("Loading packages in repository %s", repo.Path()) list, err := pkg.ReadLocalPackages(repo, repo.Path()) if err != nil { return err http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/syscfg/syscfg.go ---------------------------------------------------------------------- diff --git a/newt/syscfg/syscfg.go b/newt/syscfg/syscfg.go new file mode 100644 index 0000000..c94abfb --- /dev/null +++ b/newt/syscfg/syscfg.go @@ -0,0 +1,801 @@ +/** + * 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 syscfg + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "sort" + "strconv" + "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/util" +) + +const SYSCFG_INCLUDE_SUBDIR = "include/syscfg" +const SYSCFG_HEADER_FILENAME = "syscfg.h" + +const SYSCFG_PREFIX_API = "MYNEWT_API_" +const SYSCFG_PREFIX_PKG = "MYNEWT_PKG_" +const SYSCFG_PREFIX_SETTING = "MYNEWT_VAL_" + +type CfgSettingType int + +const ( + CFG_SETTING_TYPE_RAW CfgSettingType = iota + CFG_SETTING_TYPE_TASK_PRIO + CFG_SETTING_TYPE_INTERRUPT_PRIO +) + +const SYSCFG_PRIO_ANY = "any" + +// Reserve last 16 priorities for the system (sanity, idle). +const SYSCFG_TASK_PRIO_MAX = 0xef + +// The range of interrupt priorities is hardware dependent, so don't limit +// these here. +const SYSCFG_INTERRUPT_PRIO_MAX = 0xffffffff + +var cfgSettingNameTypeMap = map[string]CfgSettingType{ + "raw": CFG_SETTING_TYPE_RAW, + "task_priority": CFG_SETTING_TYPE_TASK_PRIO, + "interrupt_priority": CFG_SETTING_TYPE_INTERRUPT_PRIO, +} + +type CfgPoint struct { + Value string + Source *pkg.LocalPackage +} + +type CfgEntry struct { + Name string + Value string + History []CfgPoint + Description string + SettingType CfgSettingType +} + +type Cfg map[string]CfgEntry + +type cfgRoster struct { + settings map[string]string + pkgsPresent map[string]bool + apisPresent map[string]bool +} + +func WritePreamble(w io.Writer) { + fmt.Fprintf(w, "/**\n * This file was generated by %s\n */\n\n", + newtutil.NewtVersionStr) +} + +func ValueIsTrue(val string) bool { + if val == "" { + return false + } + + i, err := util.AtoiNoOct(val) + if err == nil && i == 0 { + return false + } + + return true +} + +func Features(cfg Cfg) map[string]bool { + features := map[string]bool{} + for k, v := range cfg { + if v.IsTrue() { + features[k] = true + } + } + + return features +} + +func FeaturesForLpkg(cfg Cfg, lpkg *pkg.LocalPackage) map[string]bool { + features := Features(cfg) + + for k, v := range lpkg.InjectedSettings() { + _, ok := features[k] + if ok { + log.Warnf("Attempt to override syscfg setting %s with "+ + "injected feature from package %s", k, lpkg.Name()) + } else { + if ValueIsTrue(v) { + features[k] = true + } + } + } + + return features +} + +func (point CfgPoint) Name() string { + if point.Source == nil { + return "newt" + } else { + return point.Source.Name() + } +} + +func (entry *CfgEntry) IsTrue() bool { + return ValueIsTrue(entry.Value) +} + +func appendValue(entry *CfgEntry, lpkg *pkg.LocalPackage, value interface{}) { + strval := fmt.Sprintf("%+v", value) + point := CfgPoint{Value: strval, Source: lpkg} + entry.History = append(entry.History, point) + entry.Value = strval +} + +func FeatureToCflag(featureName string) string { + return fmt.Sprintf("-D%s=1", settingName(featureName)) +} + +func stringValue(val interface{}) string { + return strings.TrimSpace(cast.ToString(val)) +} + +func readSetting(name string, lpkg *pkg.LocalPackage, + vals map[interface{}]interface{}) (CfgEntry, error) { + + entry := CfgEntry{} + + entry.Name = name + entry.Description = stringValue(vals["description"]) + entry.Value = stringValue(vals["value"]) + if vals["type"] == nil { + entry.SettingType = CFG_SETTING_TYPE_RAW + } else { + var ok bool + typename := stringValue(vals["type"]) + entry.SettingType, ok = cfgSettingNameTypeMap[typename] + if !ok { + return entry, util.FmtNewtError( + "setting %s specifies invalid type: %s", name, typename) + } + } + + appendValue(&entry, lpkg, entry.Value) + + return entry, nil +} + +func readOnce(cfg Cfg, lpkg *pkg.LocalPackage) error { + v := lpkg.Viper + + features := FeaturesForLpkg(cfg, lpkg) + settings := newtutil.GetStringMapFeatures(v, features, "pkg.syscfg_defs") + if settings != nil { + for k, v := range settings { + vals := v.(map[interface{}]interface{}) + entry, err := readSetting(k, lpkg, vals) + if err != nil { + return util.FmtNewtError("Config for package %s: %s", + lpkg.Name(), err.Error()) + } + + if _, exists := cfg[k]; exists { + // XXX: Better error message. + return util.FmtNewtError("setting %s redefined", k) + } + cfg[k] = entry + } + } + + values := newtutil.GetStringMapFeatures(v, features, "pkg.syscfg_vals") + if values != nil { + for k, v := range values { + entry, ok := cfg[k] + if ok { + appendValue(&entry, lpkg, v) + cfg[k] = entry + } else { + log.Warnf("ignoring override of undefined setting; "+ + "%s sets %s=%+v", lpkg.Name(), k, v) + } + + } + } + + return nil +} + +func Log(cfg Cfg) { + keys := make([]string, len(cfg)) + i := 0 + for k, _ := range cfg { + keys[i] = k + i++ + } + sort.Strings(keys) + + log.Debugf("syscfg settings (%d entries):", len(cfg)) + for _, k := range keys { + entry := cfg[k] + + str := fmt.Sprintf(" %s=%s [", k, entry.Value) + + for i, p := range entry.History { + if i != 0 { + str += ", " + } + str += fmt.Sprintf("%s:%s", p.Name(), p.Value) + } + str += "]" + + log.Debug(str) + } +} + +func escapeStr(s string) string { + s = strings.Replace(s, "/", "_", -1) + s = strings.Replace(s, "-", "_", -1) + s = strings.Replace(s, " ", "_", -1) + s = strings.ToUpper(s) + return s +} + +func isSettingVal(s string) bool { + return strings.HasPrefix(s, SYSCFG_PREFIX_SETTING) +} + +func isPkgVal(s string) bool { + return strings.HasPrefix(s, SYSCFG_PREFIX_PKG) +} + +func isApiVal(s string) bool { + return strings.HasPrefix(s, SYSCFG_PREFIX_API) +} + +func settingName(setting string) string { + return SYSCFG_PREFIX_SETTING + escapeStr(setting) +} + +func pkgPresentName(pkgName string) string { + return SYSCFG_PREFIX_PKG + escapeStr(pkgName) +} + +func apiPresentName(apiName string) string { + return SYSCFG_PREFIX_API + strings.ToUpper(apiName) +} + +func Read(lpkgs []*pkg.LocalPackage, apis []string, + injectedSettings map[string]string) (Cfg, error) { + + cfg := Cfg{} + for k, v := range injectedSettings { + cfg[k] = CfgEntry{ + Name: k, + Description: "Injected setting", + Value: v, + History: []CfgPoint{{ + Value: v, + Source: nil, + }}, + } + } + + // Read system configuration files. In case of conflicting settings, the + // higher priority pacakge's setting wins. Package priorities are assigned + // as follows (highest priority first): + // * target + // * app (if present) + // * unittest (if no app) + // * bsp + + var app *pkg.LocalPackage + var bsp *pkg.LocalPackage + var target *pkg.LocalPackage + var unittest *pkg.LocalPackage + + for _, lpkg := range lpkgs { + switch lpkg.Type() { + case pkg.PACKAGE_TYPE_LIB: + if err := readOnce(cfg, lpkg); err != nil { + return cfg, err + } + + case pkg.PACKAGE_TYPE_APP: + app = lpkg + + case pkg.PACKAGE_TYPE_BSP: + bsp = lpkg + + case pkg.PACKAGE_TYPE_TARGET: + target = lpkg + + case pkg.PACKAGE_TYPE_UNITTEST: + unittest = lpkg + } + } + + if bsp != nil { + if err := readOnce(cfg, bsp); err != nil { + return cfg, err + } + } + if app != nil { + if err := readOnce(cfg, app); err != nil { + return cfg, err + } + } else if unittest != nil { + if err := readOnce(cfg, unittest); err != nil { + return cfg, err + } + } + if target != nil { + if err := readOnce(cfg, target); err != nil { + return cfg, err + } + } + + roster := buildCfgRoster(cfg, lpkgs, apis) + if err := fixupSettings(cfg, roster); err != nil { + return cfg, err + } + + return cfg, nil +} + +func mostRecentPoint(entry CfgEntry) CfgPoint { + if len(entry.History) == 0 { + panic("invalid cfg entry; len(history) == 0") + } + + return entry.History[len(entry.History)-1] +} + +func calcPriorities(cfg Cfg, settingType CfgSettingType, max int, + allowDups bool) error { + + // setting-name => entry + anyEntries := map[string]CfgEntry{} + + // priority-value => entry + valEntries := map[int]CfgEntry{} + + for name, entry := range cfg { + if entry.SettingType == settingType { + if entry.Value == SYSCFG_PRIO_ANY { + anyEntries[name] = entry + } else { + prio, err := util.AtoiNoOct(entry.Value) + if err != nil { + return util.FmtNewtError( + "invalid priority value: setting=%s value=%s pkg=%s", + name, entry.Value, entry.History[0].Name()) + } + + if prio > max { + return util.FmtNewtError( + "invalid priority value: value too great (> %d); "+ + "setting=%s value=%s pkg=%s", + max, entry.Name, entry.Value, + mostRecentPoint(entry).Name()) + } + + if !allowDups { + if oldEntry, ok := valEntries[prio]; ok { + return util.FmtNewtError( + "duplicate priority value: setting1=%s "+ + "setting2=%s pkg1=%s pkg2=%s value=%s", + oldEntry.Name, entry.Name, entry.Value, + oldEntry.History[0].Name(), + entry.History[0].Name()) + } + } + + valEntries[prio] = entry + } + } + } + + greatest := 0 + for prio, _ := range valEntries { + if prio > greatest { + greatest = prio + } + } + + anyNames := make([]string, 0, len(anyEntries)) + for name, _ := range anyEntries { + anyNames = append(anyNames, name) + } + sort.Strings(anyNames) + + for _, name := range anyNames { + entry := anyEntries[name] + + greatest++ + if greatest > max { + return util.FmtNewtError("could not assign 'any' priority: "+ + "value too great (> %d); setting=%s value=%s pkg=%s", + max, name, greatest, + mostRecentPoint(entry).Name()) + } + + entry.Value = strconv.Itoa(greatest) + cfg[name] = entry + } + + return nil +} + +func writeCheckMacros(w io.Writer) { + s := `/** + * These macros exists to ensure code includes this header when needed. If + * code checks the existence of a setting directly via ifdef without including + * this header, the setting macro will silently evaluate to 0. In contrast, an + * attempt to use these macros without including this header will result in a + * compiler error. + */ +#define MYNEWT_VAL(x) MYNEWT_VAL_ ## x +#define MYNEWT_PKG(x) MYNEWT_PKG_ ## x +#define MYNEWT_API(x) MYNEWT_API_ ## x +` + fmt.Fprintf(w, "%s\n", s) +} + +func writeComment(entry CfgEntry, w io.Writer) { + if len(entry.History) > 1 { + fmt.Fprintf(w, "/* Overridden by %s (defined by %s) */\n", + mostRecentPoint(entry).Name(), + entry.History[0].Name()) + } +} + +func writeDefine(key string, value string, w io.Writer) { + fmt.Fprintf(w, "#ifndef %s\n", key) + fmt.Fprintf(w, "#define %s (%s)\n", key, value) + fmt.Fprintf(w, "#endif\n") +} + +func specialValues(cfg Cfg) (apis, pkgs, settings []string) { + for _, entry := range cfg { + if isApiVal(entry.Value) { + apis = append(apis, entry.Value) + } else if isPkgVal(entry.Value) { + pkgs = append(pkgs, entry.Value) + } else if isSettingVal(entry.Value) { + settings = append(settings, entry.Value) + } + } + + return +} + +func buildCfgRoster(cfg Cfg, lpkgs []*pkg.LocalPackage, + apis []string) cfgRoster { + + roster := cfgRoster{ + settings: make(map[string]string, len(cfg)), + pkgsPresent: make(map[string]bool, len(lpkgs)), + apisPresent: make(map[string]bool, len(apis)), + } + + for k, v := range cfg { + roster.settings[settingName(k)] = v.Value + } + + for _, v := range lpkgs { + roster.pkgsPresent[pkgPresentName(v.Name())] = true + } + + for _, v := range apis { + roster.apisPresent[apiPresentName(v)] = true + } + + apisNotPresent, pkgsNotPresent, _ := specialValues(cfg) + + for _, v := range apisNotPresent { + _, ok := roster.apisPresent[v] + if !ok { + roster.apisPresent[v] = false + } + } + + for _, v := range pkgsNotPresent { + _, ok := roster.pkgsPresent[v] + if !ok { + roster.pkgsPresent[v] = false + } + } + + return roster +} + +func settingValueToConstant(value string, + roster cfgRoster) (string, bool, error) { + + seen := map[string]struct{}{} + curVal := value + for { + v, ok := roster.settings[curVal] + if ok { + if _, ok := seen[v]; ok { + return "", false, util.FmtNewtError("Syscfg cycle detected: "+ + "%s <==> %s", value, v) + } + seen[v] = struct{}{} + curVal = v + } else { + break + } + } + if curVal != value { + return curVal, true, nil + } + + v, ok := roster.apisPresent[value] + if ok { + if v { + return "1", true, nil + } else { + return "0", true, nil + } + } + + v, ok = roster.pkgsPresent[value] + if ok { + if v { + return "1", true, nil + } else { + return "0", true, nil + } + } + + return value, false, nil +} + +func fixupSettings(cfg Cfg, roster cfgRoster) error { + for k, entry := range cfg { + value, changed, err := settingValueToConstant(entry.Value, roster) + if err != nil { + return err + } + + if changed { + entry.Value = value + cfg[k] = entry + } + } + + return nil +} + +func UnfixedValue(entry CfgEntry) string { + point := mostRecentPoint(entry) + return point.Value +} + +func EntriesByPkg(cfg Cfg) map[string][]CfgEntry { + pkgEntries := map[string][]CfgEntry{} + for _, v := range cfg { + name := v.History[0].Name() + pkgEntries[name] = append(pkgEntries[name], v) + } + return pkgEntries +} + +func writeSettingsOnePkg(cfg Cfg, pkgName string, pkgEntries []CfgEntry, + w io.Writer) { + + fmt.Fprintf(w, "/*** %s */\n", pkgName) + + names := make([]string, len(pkgEntries), len(pkgEntries)) + for i, entry := range pkgEntries { + names[i] = entry.Name + } + sort.Strings(names) + + first := true + for _, n := range names { + entry := cfg[n] + if entry.Value != "" { + if first { + first = false + } else { + fmt.Fprintf(w, "\n") + } + + writeComment(entry, w) + writeDefine(settingName(n), entry.Value, w) + } + } +} + +func writeSettings(cfg Cfg, w io.Writer) { + // Group settings by package name so that the generated header file is + // easier to readOnce. + pkgEntries := EntriesByPkg(cfg) + for _, v := range cfg { + name := v.History[0].Name() + pkgEntries[name] = append(pkgEntries[name], v) + } + + pkgNames := make([]string, 0, len(pkgEntries)) + for name, _ := range pkgEntries { + pkgNames = append(pkgNames, name) + } + sort.Strings(pkgNames) + + fmt.Fprintf(w, "/***** Settings */\n") + + for _, name := range pkgNames { + fmt.Fprintf(w, "\n") + entries := pkgEntries[name] + writeSettingsOnePkg(cfg, name, entries, w) + } +} + +func writePkgsPresent(roster cfgRoster, w io.Writer) { + present := make([]string, 0, len(roster.pkgsPresent)) + notPresent := make([]string, 0, len(roster.pkgsPresent)) + for k, v := range roster.pkgsPresent { + if v { + present = append(present, k) + } else { + notPresent = append(notPresent, k) + } + } + + sort.Strings(present) + sort.Strings(notPresent) + + fmt.Fprintf(w, "/*** Packages (present) */\n") + for _, symbol := range present { + fmt.Fprintf(w, "\n") + writeDefine(symbol, "1", w) + } + + fmt.Fprintf(w, "\n") + fmt.Fprintf(w, "/*** Packages (not present)*/\n") + for _, symbol := range notPresent { + fmt.Fprintf(w, "\n") + writeDefine(symbol, "0", w) + } +} + +func writeApisPresent(roster cfgRoster, w io.Writer) { + present := make([]string, 0, len(roster.apisPresent)) + notPresent := make([]string, 0, len(roster.apisPresent)) + for k, v := range roster.apisPresent { + if v { + present = append(present, k) + } else { + notPresent = append(notPresent, k) + } + } + + sort.Strings(present) + sort.Strings(notPresent) + + fmt.Fprintf(w, "/*** APIs (present) */\n") + for _, symbol := range present { + fmt.Fprintf(w, "\n") + writeDefine(symbol, "1", w) + } + + fmt.Fprintf(w, "\n") + fmt.Fprintf(w, "/*** APIs (not present) */\n") + for _, symbol := range notPresent { + writeDefine(symbol, "0", w) + fmt.Fprintf(w, "\n") + } +} + +func write(cfg Cfg, roster cfgRoster, w io.Writer) { + WritePreamble(w) + + fmt.Fprintf(w, "#ifndef H_MYNEWT_SYSCFG_\n") + fmt.Fprintf(w, "#define H_MYNEWT_SYSCFG_\n\n") + + writeCheckMacros(w) + fmt.Fprintf(w, "\n") + + writeSettings(cfg, w) + fmt.Fprintf(w, "\n") + + writePkgsPresent(roster, w) + fmt.Fprintf(w, "\n") + + writeApisPresent(roster, w) + fmt.Fprintf(w, "\n") + + fmt.Fprintf(w, "#endif\n") +} + +func writeRequired(contents []byte, path string) (bool, error) { + oldHeader, 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(oldHeader, contents) + return rc != 0, nil +} + +func headerPath(targetPath string) string { + return fmt.Sprintf("%s/%s/%s", targetPath, SYSCFG_INCLUDE_SUBDIR, + SYSCFG_HEADER_FILENAME) +} + +func EnsureWritten(cfg Cfg, lpkgs []*pkg.LocalPackage, + apis []string, targetPath string) error { + + if err := calcPriorities(cfg, CFG_SETTING_TYPE_TASK_PRIO, + SYSCFG_TASK_PRIO_MAX, false); err != nil { + + return err + } + + if err := calcPriorities(cfg, CFG_SETTING_TYPE_INTERRUPT_PRIO, + SYSCFG_INTERRUPT_PRIO_MAX, true); err != nil { + + return err + } + + roster := buildCfgRoster(cfg, lpkgs, apis) + if err := fixupSettings(cfg, roster); err != nil { + return err + } + + buf := bytes.Buffer{} + write(cfg, roster, &buf) + + path := headerPath(targetPath) + + writeReqd, err := writeRequired(buf.Bytes(), path) + if err != nil { + return err + } + if !writeReqd { + log.Debugf("syscfg unchanged; not writing header file (%s).", path) + return nil + } + + log.Debugf("syscfg 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 +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/sysinit/sysinit.go ---------------------------------------------------------------------- diff --git a/newt/sysinit/sysinit.go b/newt/sysinit/sysinit.go new file mode 100644 index 0000000..8e8188b --- /dev/null +++ b/newt/sysinit/sysinit.go @@ -0,0 +1,154 @@ +/** + * 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 sysinit + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "sort" + + log "github.com/Sirupsen/logrus" + + "mynewt.apache.org/newt/newt/pkg" + "mynewt.apache.org/newt/newt/syscfg" + "mynewt.apache.org/newt/util" +) + +const FILENAME = "sysinit.c" +const SYSINIT_FN_SIG = `void +sysinit(void) +{ +` + +func buildStageMap(pkgs []*pkg.LocalPackage) map[int][]*pkg.LocalPackage { + sm := map[int][]*pkg.LocalPackage{} + + for _, p := range pkgs { + stage := p.InitStage() + sm[stage] = append(sm[stage], p) + } + + return sm +} + +func writePrototypes(pkgs []*pkg.LocalPackage, w io.Writer) { + sorted := pkg.SortLclPkgs(pkgs) + for _, p := range sorted { + fmt.Fprintf(w, "void %s(void);\n", p.InitFnName()) + } +} + +func writeStage(stage int, pkgs []*pkg.LocalPackage, w io.Writer) { + sorted := pkg.SortLclPkgs(pkgs) + + fmt.Fprintf(w, " /*** Stage %d */\n", stage) + for i, p := range sorted { + fmt.Fprintf(w, " /* %d.%d: %s */\n", stage, i, p.Name()) + fmt.Fprintf(w, " %s();\n", p.InitFnName()) + } +} + +func onlyPkgsWithInit(pkgs []*pkg.LocalPackage) []*pkg.LocalPackage { + good := make([]*pkg.LocalPackage, 0, len(pkgs)) + for _, p := range pkgs { + if p.InitFnName() != "" { + good = append(good, p) + } + } + + return good +} + +func write(pkgs []*pkg.LocalPackage, w io.Writer) { + goodPkgs := onlyPkgsWithInit(pkgs) + stageMap := buildStageMap(goodPkgs) + + i := 0 + stages := make([]int, len(stageMap)) + for k, _ := range stageMap { + stages[i] = k + i++ + } + sort.Ints(stages) + + syscfg.WritePreamble(w) + + writePrototypes(goodPkgs, w) + fmt.Fprintf(w, "\n") + + fmt.Fprintf(w, "%s", SYSINIT_FN_SIG) + for i, s := range stages { + if i != 0 { + fmt.Fprintf(w, "\n") + } + + writeStage(s, stageMap[s], w) + } + + fmt.Fprintf(w, "}\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, targetPath string) error { + buf := bytes.Buffer{} + write(pkgs, &buf) + + path := fmt.Sprintf("%s/src/%s", targetPath, FILENAME) + + 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 +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/toolchain/compiler.go ---------------------------------------------------------------------- diff --git a/newt/toolchain/compiler.go b/newt/toolchain/compiler.go index b032d97..a961051 100644 --- a/newt/toolchain/compiler.go +++ b/newt/toolchain/compiler.go @@ -153,6 +153,10 @@ func addFlags(flagType string, orig []string, new []string) []string { return combined } +func (ci *CompilerInfo) AddCflags(cflags []string) { + ci.Cflags = addFlags("cflag", ci.Cflags, cflags) +} + func (ci *CompilerInfo) AddCompilerInfo(newCi *CompilerInfo) { ci.Includes = append(ci.Includes, newCi.Includes...) ci.Cflags = addFlags("cflag", ci.Cflags, newCi.Cflags) @@ -168,7 +172,7 @@ func NewCompiler(compilerDir string, dstDir string, c := &Compiler{ ObjPathList: map[string]bool{}, dstDir: filepath.Clean(dstDir), - extraDeps: []string{compilerDir + COMPILER_FILENAME}, + extraDeps: []string{}, } c.depTracker = NewDepTracker(c) http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/toolchain/deps.go ---------------------------------------------------------------------- diff --git a/newt/toolchain/deps.go b/newt/toolchain/deps.go index a50e265..e54c255 100644 --- a/newt/toolchain/deps.go +++ b/newt/toolchain/deps.go @@ -165,6 +165,7 @@ func (tracker *DepTracker) CompileRequired(srcFile string, if err != nil { return false, err } + if commandHasChanged(objFile, cmd) { util.StatusMessage(util.VERBOSITY_VERBOSE, "%s - rebuild required; "+ "different command\n", srcFile) @@ -175,6 +176,13 @@ func (tracker *DepTracker) CompileRequired(srcFile string, return true, nil } + if util.NodeNotExist(depFile) { + err := tracker.compiler.GenDepsForFile(srcFile) + if err != nil { + return false, err + } + } + srcModTime, err := util.FileModificationTime(srcFile) if err != nil { return false, err http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/vendor/mynewt.apache.org/newt/DISCLAIMER ---------------------------------------------------------------------- diff --git a/newt/vendor/mynewt.apache.org/newt/DISCLAIMER b/newt/vendor/mynewt.apache.org/newt/DISCLAIMER deleted file mode 100644 index 1600825..0000000 --- a/newt/vendor/mynewt.apache.org/newt/DISCLAIMER +++ /dev/null @@ -1,8 +0,0 @@ -Apache Mynewt is an effort undergoing incubation at The Apache Software -Foundation (ASF), sponsored by the Incubator PMC. Incubation is -required of all newly accepted projects until a further review indicates -that the infrastructure, communications, and decision making process -have stabilized in a manner consistent with other successful ASF -projects. While incubation status is not necessarily a reflection of the -completeness or stability of the code, it does indicate that the project -has yet to be fully endorsed by the ASF. http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/vendor/mynewt.apache.org/newt/LICENSE ---------------------------------------------------------------------- diff --git a/newt/vendor/mynewt.apache.org/newt/LICENSE b/newt/vendor/mynewt.apache.org/newt/LICENSE deleted file mode 100644 index 88a6f68..0000000 --- a/newt/vendor/mynewt.apache.org/newt/LICENSE +++ /dev/null @@ -1,244 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed 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. - -This product bundles pretty, which is available under the MIT license. For -details, see newt/vendor/github.com/kr/pretty/License - -This product bundles kr/text, which is available under the MIT license. For -details, see newt/vendor/github.com/kr/text/License - -This product bundles mapstructure, which is available under the MIT license. -For details, see newt/vendor/github.com/mitchellh/mapstructure/LICENSE - -This product bundles logrus, which is available under the MIT license. For -details, see newt/vendor/github.com/Sirupsen/logrus/LICENSE - -This product bundles Cast, which is available under the MIT license. For -details, see newt/vendor/github.com/spf13/cast/LICENSE - -This product bundles jWalterWeatherman, which is available under the MIT -license. For details, see -newt/vendor/github.com/spf13/jwalterweatherman/LICENSE - -This product bundles pflag, which is available under the "3-clause BSD" -license. For details, see newt/vendor/github.com/spf13/pflag/LICENSE - -This product bundles the unix Go package, which is available under the -"3-clause BSD" license. For details, see newt/vendor/golang.org/x/sys/LICENSE - -This product bundles fsnotify.v1, which is available under the "3-clause BSD" -license. For details, see newt/vendor/gopkg.in/fsnotify.v1/LICENSE - -This product bundles yaml.v2's Go port of libyaml, which is available under the -MIT license. For details, see: - * yaml/apic.go - * yaml/emitterc.go - * yaml/parserc.go - * yaml/readerc.go - * yaml/scannerc.go - * yaml/writerc.go - * yaml/yamlh.go - * yaml/yamlprivateh.go - -This product bundles viper, which is available under the MIT license. For -details, see: - * viper/LICENSE http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/vendor/mynewt.apache.org/newt/NOTICE ---------------------------------------------------------------------- diff --git a/newt/vendor/mynewt.apache.org/newt/NOTICE b/newt/vendor/mynewt.apache.org/newt/NOTICE deleted file mode 100644 index 94bea73..0000000 --- a/newt/vendor/mynewt.apache.org/newt/NOTICE +++ /dev/null @@ -1,8 +0,0 @@ -Apache Mynewt (incubating) -Copyright 2015-2016 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -Portions of this software were developed at -Runtime Inc, copyright 2015. http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0ae71ef1/newt/vendor/mynewt.apache.org/newt/util/util.go ---------------------------------------------------------------------- diff --git a/newt/vendor/mynewt.apache.org/newt/util/util.go b/newt/vendor/mynewt.apache.org/newt/util/util.go index 27b407c..930c24e 100644 --- a/newt/vendor/mynewt.apache.org/newt/util/util.go +++ b/newt/vendor/mynewt.apache.org/newt/util/util.go @@ -32,6 +32,7 @@ import ( "path/filepath" "runtime" "sort" + "strconv" "strings" "syscall" "time" @@ -422,3 +423,23 @@ func SortFields(wsSepStrings ...string) []string { sort.Strings(slice) return slice } + +func AtoiNoOct(s string) (int, error) { + var runLen int + for runLen = 0; runLen < len(s)-1; runLen++ { + if s[runLen] != '0' || s[runLen+1] == 'x' { + break + } + } + + if runLen > 0 { + s = s[runLen:] + } + + i, err := strconv.ParseInt(s, 0, 0) + if err != nil { + return 0, NewNewtError(err.Error()) + } + + return int(i), nil +}