http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/e31a7d31/newt/symbol/symbol.go ---------------------------------------------------------------------- diff --git a/newt/symbol/symbol.go b/newt/symbol/symbol.go deleted file mode 100644 index 9d155ca..0000000 --- a/newt/symbol/symbol.go +++ /dev/null @@ -1,322 +0,0 @@ -/** - * 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. - */ - -/* this file maintains a list of all the symbols from a */ - -package symbol - -import ( - "fmt" - "sort" - "strings" - - "mynewt.apache.org/newt/util" -) - -type SymbolInfo struct { - Bpkg string - Name string - Code string - Section string - Ext string - Size int - Loc int -} - -type SymbolMap map[string]SymbolInfo - -func NewSymbolMap() *SymbolMap { - val := &SymbolMap{} - return val -} - -func NewSymbolInfo() *SymbolInfo { - val := &SymbolInfo{} - return val -} - -func NewElfSymbol(name string) *SymbolInfo { - val := NewSymbolInfo() - val.Name = name - val.Ext = ".elf" - return val -} - -func (s *SymbolMap) Add(info SymbolInfo) { - (*s)[info.Name] = info -} - -func (s *SymbolMap) GlobalFunctionsOnly() *SymbolMap { - s3 := NewSymbolMap() - - for _, info1 := range *s { - if info1.IsFunction() && !info1.IsLocal() { - s3.Add(info1) - } - } - return s3 -} - -func (s *SymbolMap) GlobalDataOnly() *SymbolMap { - s3 := NewSymbolMap() - - for _, info1 := range *s { - if !info1.IsFunction() && !info1.IsLocal() { - s3.Add(info1) - } - } - return s3 -} - -func (s *SymbolMap) Packages() map[string]bool { - pkg := make(map[string]bool) - for _, info1 := range *s { - pkg[info1.Bpkg] = true - } - return pkg -} - -func IdenticalUnion(s1 *SymbolMap, s2 *SymbolMap, comparePkg bool, - compareAddr bool) (error, *SymbolMap, *SymbolMap) { - s3 := NewSymbolMap() - s_no := NewSymbolMap() - var err_str string - var err error - /* look through all symbols in S1 and if they are in s1, - * add to new map s3 */ - - for name, info1 := range *s1 { - if info2, ok := (*s2)[name]; ok { - var pkg bool - var addr bool - - if comparePkg { - pkg = info1.Bpkg == info2.Bpkg - } else { - pkg = true - } - - if compareAddr { - addr = info1.Loc == info2.Loc - } else { - addr = true - } - - /* compare to info 1 */ - if info1.Code == info2.Code && - info1.Size == info2.Size && pkg && addr { - s3.Add(info1) - } else if !info1.IsLocal() && !info1.IsFunction() { - /* Here is an unusual case. We have a global data - * symbol (bss or data) with the same name that is used - * in both apps. If code is linked against both of these - * the code in the loader will call one while the code in - * the app will call the other. If the intention was for - * these to be the same, then things are bad. */ - if err_str == "" { - err_str = "There are global symbols with the same name that " + - "are access via the loader and split application. These " + - "symbols are either different sizes or from different " + - "packages. Reconcile this issue before buidling. If the " + - "symbols are intended to be shared by both, move the " + - "symbol to a package that is shared by both apps. If " + - "the symbols are distict (not shared), then make them " + - "static or rename them so they do not conflict" + - "\nNon Matching Symbols:\n" - } - - err_str = err_str + fmt.Sprintf("%s-%s\n", info1.Sprintf(), info2.Sprintf()) - } else { - info1.Name = info1.Name + "(app)" - info2.Name = info2.Name + "(loader)" - s_no.Add(info1) - s_no.Add(info2) - } - } - } - - if err_str != "" { - err = util.NewNewtError(err_str) - } - return err, s3, s_no -} - -type SymbolMapIterator func(s *SymbolInfo) - -func sprintfSi(si *SymbolInfo) string { - str := fmt.Sprintf(" %32s(%4s) (%8s) -- (%12s) %5d (0x%08x) from %s\n", - (*si).Name, (*si).Ext, (*si).Code, (*si).Section, - (*si).Size, (*si).Loc, (*si).Bpkg) - return str -} - -func dumpSi(si *SymbolInfo) { - fmt.Printf(sprintfSi(si)) -} - -func (si *SymbolInfo) Dump() { - dumpSi(si) -} - -func (si *SymbolInfo) Sprintf() string { - return sprintfSi(si) -} - -func (si *SymbolInfo) IsLocal() bool { - val := (*si).Code[:1] - - if val == "l" { - return true - } - return false -} - -func (si *SymbolInfo) IsWeak() bool { - val := (*si).Code[1:2] - - if val == "w" { - return true - } - return false -} - -func (si *SymbolInfo) IsDebug() bool { - val := (*si).Code[5:6] - - if val == "d" { - return true - } - return false -} - -func (si *SymbolInfo) IsSection(section string) bool { - val := (*si).Section - return strings.HasPrefix(val, section) -} - -func (si *SymbolInfo) IsFile() bool { - val := (*si).Code[6:7] - - if val == "f" { - return true - } - return false -} - -func (si *SymbolInfo) IsFunction() bool { - val := (*si).Code[6:7] - - if val == "F" { - return true - } - return false -} - -func (s *SymbolMap) FilterPkg(pname string) *SymbolMap { - sm := NewSymbolMap() - for _, info1 := range *s { - if pname != "" && pname == info1.Bpkg { - sm.Add(info1) - } - } - return sm -} - -func (s *SymbolMap) String(name string) string { - // To store the keys in slice in sorted order - var keys []string - for k := range *s { - keys = append(keys, k) - } - sort.Strings(keys) - - // To perform the opertion you want - out := fmt.Sprintf("Dumping symbols in file: %s\n", name) - for _, k := range keys { - info1 := (*s)[k] - out += info1.Sprintf() - } - return out -} - -func (s *SymbolMap) Dump(name string) { - - // To store the keys in slice in sorted order - var keys []string - for k := range *s { - keys = append(keys, k) - } - sort.Strings(keys) - - // To perform the opertion you want - fmt.Printf("Dumping symbols in file: %s\n", name) - for _, k := range keys { - info1 := (*s)[k] - info1.Dump() - } -} - -// Merge - merges given maps into 1 map -// values will be overridden by last matching key - value -func (s1 *SymbolMap) Merge(s2 *SymbolMap) (*SymbolMap, error) { - - for k, v := range *s2 { - - if val, ok := (*s1)[k]; ok { - /* We already have this in the MAP */ - if val.IsWeak() && !v.IsWeak() { - (*s1)[k] = v - } else if v.IsWeak() && !val.IsWeak() { - /* nothing to do here as this is OK not to replace */ - } else if v.IsLocal() && val.IsLocal() { - /* two locals that must conflict with name */ - /* have to have separate instances of these */ - util.StatusMessage(util.VERBOSITY_VERBOSE, - "Local Symbol Conflict: %s from packages %s and %s \n", - v.Name, v.Bpkg, val.Bpkg) - (*s2).Remove(k) - } else { - util.StatusMessage(util.VERBOSITY_QUIET, - "Global Symbol Conflict: %s from packages %s and %s \n", - v.Name, v.Bpkg, val.Bpkg) - return nil, util.NewNewtError("Global Symbol Conflict") - } - } else { - (*s1)[k] = v - } - - } - return s1, nil -} - -func (s *SymbolMap) Remove(name string) { - delete(*s, name) -} - -func (s *SymbolMap) RemoveMap(subset *SymbolMap) { - for name, _ := range *subset { - (*s).Remove(name) - } -} - -/* Returns true if the symbol is present in the symbol map */ -func (s *SymbolMap) Find(name string) (*SymbolInfo, bool) { - val, ok := (*s)[name] - return &val, ok -}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/e31a7d31/newt/syscfg/restrict.go ---------------------------------------------------------------------- diff --git a/newt/syscfg/restrict.go b/newt/syscfg/restrict.go deleted file mode 100644 index 5f9c0f7..0000000 --- a/newt/syscfg/restrict.go +++ /dev/null @@ -1,199 +0,0 @@ -/** - * 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 ( - "fmt" - "strings" - - "mynewt.apache.org/newt/util" -) - -type CfgRestrictionCode int - -const ( - CFG_RESTRICTION_CODE_NOTNULL = iota - CFG_RESTRICTION_CODE_EXPR -) - -var cfgRestrictionNameCodeMap = map[string]CfgRestrictionCode{ - "$notnull": CFG_RESTRICTION_CODE_NOTNULL, -} - -type CfgRestrictionExpr struct { - ReqSetting string - ReqVal bool - BaseVal bool -} -type CfgRestriction struct { - BaseSetting string - Code CfgRestrictionCode - - // Only used if Code is CFG_RESTRICTION_CODE_EXPR - Expr CfgRestrictionExpr -} - -func parseRestrictionExprConsequent(field string) (string, bool) { - var val bool - var name string - - if strings.HasPrefix(field, "!") { - val = false - name = strings.TrimPrefix(field, "!") - } else { - val = true - name = field - } - - return name, val -} - -// Parses a restriction value. -// -// Currently, two forms of restrictions are supported: -// 1. "$notnull" -// 2. expression -// -// The "$notnull" string indicates that the setting must be set to something -// other than the empty string. -// -// An expression string indicates dependencies on other settings. It would be -// better to have a real expression parser. For now, only very simple -// expressions are supported. A restriction expression must be of the -// following form: -// [!]<req-setting> [if <base-val>] -// -// All setting values are interpreted as booleans. If a setting is "0", "", -// or undefined, it is false; otherwise it is true. -// -// Examples: -// # Can't enable this setting unless LOG_FCB is enabled. -// pkg.restrictions: -// LOG_FCB -// -// # Can't enable this setting unless LOG_FCB is disabled. -// pkg.restrictions: -// !LOG_FCB -// -// # Can't disable this setting unless LOG_FCB is enabled. -// pkg.restrictions: -// LOG_FCB if 0 -func readRestrictionExpr(text string) (CfgRestrictionExpr, error) { - e := CfgRestrictionExpr{} - - fields := strings.Fields(text) - switch len(fields) { - case 1: - e.ReqSetting, e.ReqVal = parseRestrictionExprConsequent(fields[0]) - e.BaseVal = true - - case 3: - if fields[1] != "if" { - return e, util.FmtNewtError("invalid restriction: %s", text) - } - e.ReqSetting, e.ReqVal = parseRestrictionExprConsequent(fields[0]) - e.BaseVal = ValueIsTrue(fields[2]) - - default: - return e, util.FmtNewtError("invalid restriction: %s", text) - } - - return e, nil -} - -func readRestriction(baseSetting string, text string) (CfgRestriction, error) { - r := CfgRestriction{ - BaseSetting: baseSetting, - } - - var ok bool - if r.Code, ok = cfgRestrictionNameCodeMap[text]; !ok { - // If the restriction text isn't a defined string, parse it as an - // expression. - r.Code = CFG_RESTRICTION_CODE_EXPR - - var err error - if r.Expr, err = readRestrictionExpr(text); err != nil { - return r, err - } - } - - return r, nil -} - -func (cfg *Cfg) violationText(entry CfgEntry, r CfgRestriction) string { - if r.Code == CFG_RESTRICTION_CODE_NOTNULL { - return entry.Name + " must not be null" - } - - str := fmt.Sprintf("%s=%s ", entry.Name, entry.Value) - if r.Expr.ReqVal { - str += fmt.Sprintf("requires %s be set", r.Expr.ReqSetting) - } else { - str += fmt.Sprintf("requires %s not be set", r.Expr.ReqSetting) - } - - str += fmt.Sprintf(", but %s", r.Expr.ReqSetting) - reqEntry, ok := cfg.Settings[r.Expr.ReqSetting] - if !ok { - str += "undefined" - } else { - str += fmt.Sprintf("=%s", reqEntry.Value) - } - - return str -} - -func (r *CfgRestriction) relevantSettingNames() []string { - switch r.Code { - case CFG_RESTRICTION_CODE_NOTNULL: - return []string{r.BaseSetting} - - case CFG_RESTRICTION_CODE_EXPR: - return []string{r.BaseSetting, r.Expr.ReqSetting} - - default: - panic("Invalid restriction code: " + string(r.Code)) - } -} - -func (cfg *Cfg) restrictionMet(r CfgRestriction) bool { - baseEntry := cfg.Settings[r.BaseSetting] - baseVal := baseEntry.IsTrue() - - switch r.Code { - case CFG_RESTRICTION_CODE_NOTNULL: - return baseEntry.Value != "" - - case CFG_RESTRICTION_CODE_EXPR: - if baseVal != r.Expr.BaseVal { - // Restriction does not apply. - return true - } - - reqEntry, ok := cfg.Settings[r.Expr.ReqSetting] - reqVal := ok && reqEntry.IsTrue() - - return reqVal == r.Expr.ReqVal - - default: - panic("Invalid restriction code: " + string(r.Code)) - } -} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/e31a7d31/newt/syscfg/syscfg.go ---------------------------------------------------------------------- diff --git a/newt/syscfg/syscfg.go b/newt/syscfg/syscfg.go deleted file mode 100644 index cac298e..0000000 --- a/newt/syscfg/syscfg.go +++ /dev/null @@ -1,1045 +0,0 @@ -/** - * 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/flash" - "mynewt.apache.org/newt/newt/interfaces" - "mynewt.apache.org/newt/newt/newtutil" - "mynewt.apache.org/newt/newt/pkg" - "mynewt.apache.org/newt/util" -) - -const HEADER_PATH = "syscfg/syscfg.h" - -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 - CFG_SETTING_TYPE_FLASH_OWNER -) - -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, - "flash_owner": CFG_SETTING_TYPE_FLASH_OWNER, -} - -type CfgPoint struct { - Value string - Source *pkg.LocalPackage -} - -type CfgEntry struct { - Name string - Value string - Description string - SettingType CfgSettingType - Restrictions []CfgRestriction - PackageDef *pkg.LocalPackage - History []CfgPoint -} - -type CfgPriority struct { - SettingName string - PackageDef *pkg.LocalPackage // package that define the setting. - PackageSrc *pkg.LocalPackage // package overriding setting value. -} - -type CfgFlashConflictCode int - -const ( - CFG_FLASH_CONFLICT_CODE_BAD_NAME CfgFlashConflictCode = iota - CFG_FLASH_CONFLICT_CODE_NOT_UNIQUE -) - -type CfgFlashConflict struct { - SettingNames []string - Code CfgFlashConflictCode -} - -type Cfg struct { - Settings map[string]CfgEntry - - //// Errors - // Overrides of undefined settings. - Orphans map[string][]CfgPoint - - // Two packages of equal priority override a setting with different - // values; not overridden by higher priority package. - Ambiguities map[string][]CfgPoint - - // Setting restrictions not met. - Violations map[string][]CfgRestriction - - // Attempted override by bottom-priority packages (libraries). - PriorityViolations []CfgPriority - - FlashConflicts []CfgFlashConflict -} - -func NewCfg() Cfg { - return Cfg{ - Settings: map[string]CfgEntry{}, - Orphans: map[string][]CfgPoint{}, - Ambiguities: map[string][]CfgPoint{}, - Violations: map[string][]CfgRestriction{}, - PriorityViolations: []CfgPriority{}, - FlashConflicts: []CfgFlashConflict{}, - } -} - -func ValueIsTrue(val string) bool { - if val == "" { - return false - } - - i, err := util.AtoiNoOct(val) - if err == nil && i == 0 { - return false - } - - return true -} - -func (cfg *Cfg) Features() map[string]bool { - features := map[string]bool{} - for k, v := range cfg.Settings { - if v.IsTrue() { - features[k] = true - } - } - - return features -} - -func (cfg *Cfg) FeaturesForLpkg(lpkg *pkg.LocalPackage) map[string]bool { - features := cfg.Features() - - 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 (point CfgPoint) IsInjected() bool { - return point.Source == nil -} - -func (entry *CfgEntry) IsTrue() bool { - return ValueIsTrue(entry.Value) -} - -func (entry *CfgEntry) appendValue(lpkg *pkg.LocalPackage, value interface{}) { - strval := stringValue(value) - point := CfgPoint{Value: strval, Source: lpkg} - entry.History = append(entry.History, point) - entry.Value = strval -} - -func historyToString(history []CfgPoint) string { - str := "[" - for i, _ := range history { - if i != 0 { - str += ", " - } - p := history[len(history)-i-1] - str += fmt.Sprintf("%s:%s", p.Name(), p.Value) - } - str += "]" - - return str -} - -func (entry *CfgEntry) ambiguities() []CfgPoint { - diffVals := false - var points []CfgPoint - - for i := 1; i < len(entry.History)-1; i++ { - cur := entry.History[len(entry.History)-i-1] - next := entry.History[len(entry.History)-i] - - // If either setting is injected, there is no ambiguity - if cur.Source == nil || next.Source == nil { - break - } - - // If the two package have different priorities, there is no ambiguity. - if normalizePkgType(cur.Source.Type()) != - normalizePkgType(next.Source.Type()) { - - break - } - - if cur.Value != next.Value { - diffVals = true - } - - if len(points) == 0 { - points = append(points, cur) - } - points = append(points, next) - } - - // If all values are identical, there is no ambiguity - if !diffVals { - points = nil - } - - return points -} - -func (entry *CfgEntry) ambiguityText() string { - points := entry.ambiguities() - if len(points) == 0 { - return "" - } - - str := fmt.Sprintf("Setting: %s, Packages: [", entry.Name) - for i, p := range points { - if i > 0 { - str += ", " - } - - str += p.Source.Name() - } - str += "]" - - return str -} - -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.PackageDef = lpkg - entry.Description = stringValue(vals["description"]) - - // The value field for setting definition is required. - valueVal, valueExist := vals["value"] - if valueExist { - entry.Value = stringValue(valueVal) - } else { - return entry, util.FmtNewtError( - "setting %s does not have required value field", name) - } - - 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) - } - } - entry.appendValue(lpkg, entry.Value) - - entry.Restrictions = []CfgRestriction{} - restrictionStrings := cast.ToStringSlice(vals["restrictions"]) - for _, rstring := range restrictionStrings { - r, err := readRestriction(name, rstring) - if err != nil { - return entry, - util.PreNewtError(err, "error parsing setting %s", name) - } - entry.Restrictions = append(entry.Restrictions, r) - } - - return entry, nil -} - -func (cfg *Cfg) readDefsOnce(lpkg *pkg.LocalPackage, - features map[string]bool) error { - v := lpkg.SyscfgV - - lfeatures := cfg.FeaturesForLpkg(lpkg) - for k, _ := range features { - lfeatures[k] = true - } - - settings := newtutil.GetStringMapFeatures(v, lfeatures, "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 oldEntry, exists := cfg.Settings[k]; exists { - // Setting already defined. Allow this only if the setting is - // injected, in which case the injected value takes precedence. - point := mostRecentPoint(oldEntry) - if !point.IsInjected() { - // XXX: Better error message. - return util.FmtNewtError("setting %s redefined", k) - } - - entry.History = append(entry.History, oldEntry.History...) - entry.Value = oldEntry.Value - } - cfg.Settings[k] = entry - } - } - - return nil -} - -func (cfg *Cfg) readValsOnce(lpkg *pkg.LocalPackage, - features map[string]bool) error { - v := lpkg.SyscfgV - - lfeatures := cfg.FeaturesForLpkg(lpkg) - for k, _ := range features { - lfeatures[k] = true - } - - values := newtutil.GetStringMapFeatures(v, lfeatures, "syscfg.vals") - for k, v := range values { - entry, ok := cfg.Settings[k] - if ok { - sourcetype := normalizePkgType(lpkg.Type()) - deftype := normalizePkgType(entry.PackageDef.Type()) - if sourcetype <= deftype { - // Overrides must come from a higher priority package. - priority := CfgPriority{ - PackageDef: entry.PackageDef, - PackageSrc: lpkg, - SettingName: k, - } - cfg.PriorityViolations = append(cfg.PriorityViolations, priority) - } else { - entry.appendValue(lpkg, v) - cfg.Settings[k] = entry - } - } else { - orphan := CfgPoint{ - Value: stringValue(v), - Source: lpkg, - } - cfg.Orphans[k] = append(cfg.Orphans[k], orphan) - } - } - - return nil -} - -func (cfg *Cfg) Log() { - keys := make([]string, len(cfg.Settings)) - i := 0 - for k, _ := range cfg.Settings { - keys[i] = k - i++ - } - sort.Strings(keys) - - log.Debugf("syscfg settings (%d entries):", len(cfg.Settings)) - for _, k := range keys { - entry := cfg.Settings[k] - - log.Debugf(" %s=%s %s", k, entry.Value, - historyToString(entry.History)) - } -} - -func (cfg *Cfg) settingsOfType(typ CfgSettingType) []CfgEntry { - entries := []CfgEntry{} - - for _, entry := range cfg.Settings { - if entry.SettingType == typ { - entries = append(entries, entry) - } - } - - return entries -} - -func (cfg *Cfg) detectViolations() { - for _, entry := range cfg.Settings { - var ev []CfgRestriction - for _, r := range entry.Restrictions { - if !cfg.restrictionMet(r) { - ev = append(ev, r) - } - } - - if ev != nil { - cfg.Violations[entry.Name] = ev - } - } -} - -func (cfg *Cfg) detectFlashConflicts(flashMap flash.FlashMap) { - entries := cfg.settingsOfType(CFG_SETTING_TYPE_FLASH_OWNER) - - areaEntryMap := map[string][]CfgEntry{} - - for _, entry := range entries { - if entry.Value != "" { - area, ok := flashMap.Areas[entry.Value] - if !ok { - conflict := CfgFlashConflict{ - SettingNames: []string{entry.Name}, - Code: CFG_FLASH_CONFLICT_CODE_BAD_NAME, - } - cfg.FlashConflicts = append(cfg.FlashConflicts, conflict) - } else { - areaEntryMap[area.Name] = - append(areaEntryMap[area.Name], entry) - } - } - } - - // Settings with type flash_owner must have unique values. - for _, entries := range areaEntryMap { - if len(entries) > 1 { - conflict := CfgFlashConflict{ - SettingNames: []string{}, - Code: CFG_FLASH_CONFLICT_CODE_NOT_UNIQUE, - } - - for _, entry := range entries { - conflict.SettingNames = - append(conflict.SettingNames, entry.Name) - } - - cfg.FlashConflicts = append(cfg.FlashConflicts, conflict) - } - } -} - -func (cfg *Cfg) flashConflictErrorText(conflict CfgFlashConflict) string { - entry := cfg.Settings[conflict.SettingNames[0]] - - switch conflict.Code { - case CFG_FLASH_CONFLICT_CODE_BAD_NAME: - return fmt.Sprintf("Setting %s specifies unknown flash area: %s\n", - entry.Name, entry.Value) - - case CFG_FLASH_CONFLICT_CODE_NOT_UNIQUE: - return fmt.Sprintf( - "Multiple flash_owner settings specify the same flash area\n"+ - " settings: %s\n"+ - " flash area: %s\n", - strings.Join(conflict.SettingNames, ", "), - entry.Value) - - default: - panic("Invalid flash conflict code: " + string(conflict.Code)) - } -} - -func historyTextOnce(settingName string, points []CfgPoint) string { - return fmt.Sprintf(" %s: %s\n", settingName, historyToString(points)) -} - -func historyText(historyMap map[string][]CfgPoint) string { - if len(historyMap) == 0 { - return "" - } - - str := "Setting history (newest -> oldest):\n" - names := make([]string, 0, len(historyMap)) - for name, _ := range historyMap { - names = append(names, name) - } - sort.Strings(names) - - for _, name := range names { - points := historyMap[name] - str += historyTextOnce(name, points) - } - - return str -} - -func (cfg *Cfg) ErrorText() string { - str := "" - - historyMap := map[string][]CfgPoint{} - - if len(cfg.Violations) > 0 { - str += "Syscfg restriction violations detected:\n" - for settingName, rslice := range cfg.Violations { - baseEntry := cfg.Settings[settingName] - historyMap[settingName] = baseEntry.History - for _, r := range rslice { - for _, name := range r.relevantSettingNames() { - reqEntry := cfg.Settings[name] - historyMap[name] = reqEntry.History - } - str += " " + cfg.violationText(baseEntry, r) + "\n" - } - } - } - - if len(cfg.Ambiguities) > 0 { - str += "Syscfg ambiguities detected:\n" - - settingNames := make([]string, 0, len(cfg.Ambiguities)) - for k, _ := range cfg.Ambiguities { - settingNames = append(settingNames, k) - } - sort.Strings(settingNames) - - for _, name := range settingNames { - entry := cfg.Settings[name] - historyMap[entry.Name] = entry.History - str += " " + entry.ambiguityText() - } - } - - if len(cfg.PriorityViolations) > 0 { - str += "Priority violations detected (Packages can only override " + - "settings defined by packages of lower priority):\n" - for _, priority := range cfg.PriorityViolations { - entry := cfg.Settings[priority.SettingName] - historyMap[priority.SettingName] = entry.History - - str += fmt.Sprintf(" Package: %s overriding setting: %s defined by %s\n", - priority.PackageSrc.Name(), priority.SettingName, priority.PackageDef.Name()) - } - } - - if len(cfg.FlashConflicts) > 0 { - str += "Flash errors detected:\n" - for _, conflict := range cfg.FlashConflicts { - for _, name := range conflict.SettingNames { - entry := cfg.Settings[name] - historyMap[name] = entry.History - } - - str += " " + cfg.flashConflictErrorText(conflict) - } - } - - if str == "" { - return "" - } - - str += "\n" + historyText(historyMap) - - return strings.TrimSpace(str) -} - -func (cfg *Cfg) WarningText() string { - str := "" - - historyMap := map[string][]CfgPoint{} - - if len(cfg.Orphans) > 0 { - settingNames := make([]string, len(cfg.Orphans)) - i := 0 - for k, _ := range cfg.Orphans { - settingNames[i] = k - i++ - } - sort.Strings(settingNames) - - str += "Ignoring override of undefined settings:" - for _, n := range settingNames { - historyMap[n] = cfg.Orphans[n] - str += fmt.Sprintf("\n %s", n) - } - } - - if str == "" { - return "" - } - - str += "\n" + historyText(historyMap) - - return str -} - -func escapeStr(s string) string { - return strings.ToUpper(util.CIdentifier(s)) -} - -func settingName(setting string) string { - return SYSCFG_PREFIX_SETTING + escapeStr(setting) -} - -func normalizePkgType(typ interfaces.PackageType) interfaces.PackageType { - switch typ { - case pkg.PACKAGE_TYPE_TARGET: - return pkg.PACKAGE_TYPE_TARGET - case pkg.PACKAGE_TYPE_APP: - return pkg.PACKAGE_TYPE_APP - case pkg.PACKAGE_TYPE_UNITTEST: - return pkg.PACKAGE_TYPE_UNITTEST - case pkg.PACKAGE_TYPE_BSP: - return pkg.PACKAGE_TYPE_BSP - default: - return pkg.PACKAGE_TYPE_LIB - } -} - -func categorizePkgs( - lpkgs []*pkg.LocalPackage) map[interfaces.PackageType][]*pkg.LocalPackage { - - pmap := map[interfaces.PackageType][]*pkg.LocalPackage{ - pkg.PACKAGE_TYPE_TARGET: []*pkg.LocalPackage{}, - pkg.PACKAGE_TYPE_APP: []*pkg.LocalPackage{}, - pkg.PACKAGE_TYPE_UNITTEST: []*pkg.LocalPackage{}, - pkg.PACKAGE_TYPE_BSP: []*pkg.LocalPackage{}, - pkg.PACKAGE_TYPE_LIB: []*pkg.LocalPackage{}, - } - - for _, lpkg := range lpkgs { - typ := normalizePkgType(lpkg.Type()) - pmap[typ] = append(pmap[typ], lpkg) - } - - for k, v := range pmap { - pmap[k] = pkg.SortLclPkgs(v) - } - - return pmap -} - -func (cfg *Cfg) readDefsForPkgType(lpkgs []*pkg.LocalPackage, - features map[string]bool) error { - - for _, lpkg := range lpkgs { - if err := cfg.readDefsOnce(lpkg, features); err != nil { - return err - } - } - return nil -} -func (cfg *Cfg) readValsForPkgType(lpkgs []*pkg.LocalPackage, - features map[string]bool) error { - - for _, lpkg := range lpkgs { - if err := cfg.readValsOnce(lpkg, features); err != nil { - return err - } - } - - return nil -} - -func (cfg *Cfg) detectAmbiguities() { - for _, entry := range cfg.Settings { - if points := entry.ambiguities(); len(points) > 0 { - cfg.Ambiguities[entry.Name] = points - } - } -} - -func Read(lpkgs []*pkg.LocalPackage, apis []string, - injectedSettings map[string]string, features map[string]bool, - flashMap flash.FlashMap) (Cfg, error) { - - cfg := NewCfg() - for k, v := range injectedSettings { - cfg.Settings[k] = CfgEntry{ - Name: k, - Description: "Injected setting", - Value: v, - History: []CfgPoint{{ - Value: v, - Source: nil, - }}, - } - - if ValueIsTrue(v) { - features[k] = true - } - } - - // 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 - // * everything else (lib, sdk, compiler) - - lpkgMap := categorizePkgs(lpkgs) - - for _, ptype := range []interfaces.PackageType{ - pkg.PACKAGE_TYPE_LIB, - pkg.PACKAGE_TYPE_BSP, - pkg.PACKAGE_TYPE_UNITTEST, - pkg.PACKAGE_TYPE_APP, - pkg.PACKAGE_TYPE_TARGET, - } { - if err := cfg.readDefsForPkgType(lpkgMap[ptype], features); err != nil { - return cfg, err - } - } - - for _, ptype := range []interfaces.PackageType{ - pkg.PACKAGE_TYPE_LIB, - pkg.PACKAGE_TYPE_BSP, - pkg.PACKAGE_TYPE_UNITTEST, - pkg.PACKAGE_TYPE_APP, - pkg.PACKAGE_TYPE_TARGET, - } { - if err := cfg.readValsForPkgType(lpkgMap[ptype], features); err != nil { - return cfg, err - } - } - - cfg.detectAmbiguities() - cfg.detectViolations() - cfg.detectFlashConflicts(flashMap) - - 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.Settings { - 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.Settings[name] = entry - } - - return nil -} - -func writeCheckMacros(w io.Writer) { - s := `/** - * This macro exists to ensure code includes this header when needed. If code - * checks the existence of a setting directly via ifdef without including this - * header, the setting macro will silently evaluate to 0. In contrast, an - * attempt to use these macros without including this header will result in a - * compiler error. - */ -#define MYNEWT_VAL(x) MYNEWT_VAL_ ## x -` - 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) { - if value == "" { - fmt.Fprintf(w, "#undef %s\n", key) - } else { - fmt.Fprintf(w, "#ifndef %s\n", key) - fmt.Fprintf(w, "#define %s (%s)\n", key, value) - fmt.Fprintf(w, "#endif\n") - } -} - -func EntriesByPkg(cfg Cfg) map[string][]CfgEntry { - pkgEntries := map[string][]CfgEntry{} - for _, v := range cfg.Settings { - name := v.History[0].Name() - pkgEntries[name] = append(pkgEntries[name], v) - } - return pkgEntries -} - -func writeSettingsOnePkg(cfg Cfg, pkgName string, pkgEntries []CfgEntry, - w io.Writer) { - - names := make([]string, len(pkgEntries), len(pkgEntries)) - for i, entry := range pkgEntries { - names[i] = entry.Name - } - - if len(names) == 0 { - return - } - sort.Strings(names) - - fmt.Fprintf(w, "/*** %s */\n", pkgName) - - first := true - for _, n := range names { - entry := cfg.Settings[n] - if 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 read. - pkgEntries := EntriesByPkg(cfg) - - pkgNames := make([]string, 0, len(pkgEntries)) - for name, _ := range pkgEntries { - pkgNames = append(pkgNames, name) - } - sort.Strings(pkgNames) - - for _, name := range pkgNames { - fmt.Fprintf(w, "\n") - entries := pkgEntries[name] - writeSettingsOnePkg(cfg, name, entries, w) - } -} - -func write(cfg Cfg, w io.Writer) { - fmt.Fprintf(w, newtutil.GeneratedPreamble()) - - 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") - - fmt.Fprintf(w, "#endif\n") -} - -func EnsureWritten(cfg Cfg, includeDir string) error { - // XXX: Detect these problems at error text generation time. - if err := calcPriorities(cfg, CFG_SETTING_TYPE_TASK_PRIO, - SYSCFG_TASK_PRIO_MAX, false); err != nil { - - return err - } - - // XXX: Detect these problems at error text generation time. - if err := calcPriorities(cfg, CFG_SETTING_TYPE_INTERRUPT_PRIO, - SYSCFG_INTERRUPT_PRIO_MAX, true); err != nil { - - return err - } - - buf := bytes.Buffer{} - write(cfg, &buf) - - path := includeDir + "/" + HEADER_PATH - - writeReqd, err := util.FileContentsChanged(path, buf.Bytes()) - 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 -} - -func KeyValueFromStr(str string) (map[string]string, error) { - vals := map[string]string{} - - if strings.TrimSpace(str) == "" { - return vals, nil - } - - // Separate syscfg vals are delimited by ':'. - fields := strings.Split(str, ":") - - // Key-value pairs are delimited by '='. If no '=' is present, assume the - // string is the key name and the value is 1. - for _, f := range fields { - if _, err := util.AtoiNoOct(f); err == nil { - return nil, util.FmtNewtError( - "Invalid setting name \"%s\"; must not be a number", f) - } - - kv := strings.SplitN(f, "=", 2) - switch len(kv) { - case 1: - vals[f] = "1" - case 2: - vals[kv[0]] = kv[1] - } - } - - return vals, nil -} - -func KeyValueToStr(syscfgKv map[string]string) string { - str := "" - - names := make([]string, 0, len(syscfgKv)) - for k, _ := range syscfgKv { - names = append(names, k) - } - sort.Strings(names) - - for i, name := range names { - if i != 0 { - str += ":" - } - - str += fmt.Sprintf("%s=%s", name, syscfgKv[name]) - } - - return str -} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/e31a7d31/newt/sysinit/sysinit.go ---------------------------------------------------------------------- diff --git a/newt/sysinit/sysinit.go b/newt/sysinit/sysinit.go deleted file mode 100644 index 29dc082..0000000 --- a/newt/sysinit/sysinit.go +++ /dev/null @@ -1,170 +0,0 @@ -/** - * 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/newtutil" - "mynewt.apache.org/newt/newt/pkg" - "mynewt.apache.org/newt/util" -) - -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 -} - -func writePrototypes(pkgs []*pkg.LocalPackage, w io.Writer) { - sorted := pkg.SortLclPkgs(pkgs) - for _, p := range sorted { - init := p.Init() - for name, _ := range init { - fmt.Fprintf(w, "void %s(void);\n", name) - } - } -} - -func writeStage(stage int, initFuncs []*initFunc, w io.Writer) { - fmt.Fprintf(w, " /*** Stage %d */\n", stage) - for i, initFunc := range initFuncs { - fmt.Fprintf(w, " /* %d.%d: %s */\n", stage, i, initFunc.pkg.Name()) - fmt.Fprintf(w, " %s();\n", initFunc.name) - } -} - -func write(pkgs []*pkg.LocalPackage, isLoader bool, - w io.Writer) { - - stageMap := buildStageMap(pkgs) - - i := 0 - stages := make([]int, len(stageMap)) - for k, _ := range stageMap { - stages[i] = k - i++ - } - sort.Ints(stages) - - fmt.Fprintf(w, newtutil.GeneratedPreamble()) - - if isLoader { - fmt.Fprintf(w, "#if SPLIT_LOADER\n\n") - } else { - fmt.Fprintf(w, "#if !SPLIT_LOADER\n\n") - } - - writePrototypes(pkgs, w) - - var fnName string - if isLoader { - fnName = "sysinit_loader" - } else { - fnName = "sysinit_app" - } - - fmt.Fprintf(w, "\n") - fmt.Fprintf(w, "void\n%s(void)\n{\n", fnName) - - for _, s := range stages { - fmt.Fprintf(w, "\n") - writeStage(s, stageMap[s], 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 { - - buf := bytes.Buffer{} - write(pkgs, isLoader, &buf) - - var path string - if isLoader { - path = fmt.Sprintf("%s/%s-sysinit-loader.c", srcDir, targetName) - } else { - path = fmt.Sprintf("%s/%s-sysinit-app.c", srcDir, targetName) - } - - writeReqd, err := writeRequired(buf.Bytes(), path) - if err != nil { - 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-newtmgr/blob/e31a7d31/newt/target/target.go ---------------------------------------------------------------------- diff --git a/newt/target/target.go b/newt/target/target.go deleted file mode 100644 index 26ca4cf..0000000 --- a/newt/target/target.go +++ /dev/null @@ -1,293 +0,0 @@ -/** - * 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 target - -import ( - "os" - "path/filepath" - "sort" - "strings" - - "mynewt.apache.org/newt/newt/pkg" - "mynewt.apache.org/newt/newt/project" - "mynewt.apache.org/newt/newt/repo" - "mynewt.apache.org/newt/util" - "mynewt.apache.org/newt/yaml" -) - -const TARGET_FILENAME string = "target.yml" -const DEFAULT_BUILD_PROFILE string = "default" - -var globalTargetMap map[string]*Target - -type Target struct { - basePkg *pkg.LocalPackage - - BspName string - AppName string - LoaderName string - BuildProfile string - - // target.yml configuration structure - Vars map[string]string -} - -func NewTarget(basePkg *pkg.LocalPackage) *Target { - target := &Target{} - target.Init(basePkg) - return target -} - -func LoadTarget(basePkg *pkg.LocalPackage) (*Target, error) { - target := NewTarget(basePkg) - if err := target.Load(basePkg); err != nil { - return nil, err - } - - return target, nil -} - -func (target *Target) Init(basePkg *pkg.LocalPackage) { - target.basePkg = basePkg -} - -func (target *Target) Load(basePkg *pkg.LocalPackage) error { - v, err := util.ReadConfig(basePkg.BasePath(), - strings.TrimSuffix(TARGET_FILENAME, ".yml")) - if err != nil { - return err - } - - target.Vars = map[string]string{} - - settings := v.AllSettings() - for k, v := range settings { - target.Vars[k] = v.(string) - } - - target.BspName = target.Vars["target.bsp"] - target.AppName = target.Vars["target.app"] - target.LoaderName = target.Vars["target.loader"] - target.BuildProfile = target.Vars["target.build_profile"] - - if target.BuildProfile == "" { - target.BuildProfile = DEFAULT_BUILD_PROFILE - } - - // Note: App not required in the case of unit tests. - - // Remember the name of the configuration file so that it can be specified - // as a dependency to the compiler. - target.basePkg.AddCfgFilename(basePkg.BasePath() + TARGET_FILENAME) - - return nil -} - -func (target *Target) Validate(appRequired bool) error { - if target.BspName == "" { - return util.NewNewtError("Target does not specify a BSP package " + - "(target.bsp)") - } - bsp := target.resolvePackageName(target.BspName) - if bsp == nil { - return util.FmtNewtError("Could not resolve BSP package: %s", - target.BspName) - } - - if bsp.Type() != pkg.PACKAGE_TYPE_BSP { - return util.FmtNewtError("bsp package (%s) is not of "+ - "type bsp; type is: %s\n", bsp.Name(), - pkg.PackageTypeNames[bsp.Type()]) - } - - if appRequired { - if target.AppName == "" { - return util.NewNewtError("Target does not specify an app " + - "package (target.app)") - } - app := target.resolvePackageName(target.AppName) - if app == nil { - return util.FmtNewtError("Could not resolve app package: %s", - target.AppName) - } - - if app.Type() != pkg.PACKAGE_TYPE_APP { - return util.FmtNewtError("target.app package (%s) is not of "+ - "type app; type is: %s\n", app.Name(), - pkg.PackageTypeNames[app.Type()]) - } - - if target.LoaderName != "" { - loader := target.resolvePackageName(target.LoaderName) - if loader == nil { - return util.FmtNewtError( - "Could not resolve loader package: %s", target.LoaderName) - } - - if loader.Type() != pkg.PACKAGE_TYPE_APP { - return util.FmtNewtError( - "target.loader package (%s) is not of type app; type "+ - "is: %s\n", loader.Name(), - pkg.PackageTypeNames[loader.Type()]) - } - } - } - - return nil -} - -func (target *Target) Package() *pkg.LocalPackage { - return target.basePkg -} - -func (target *Target) Name() string { - return target.basePkg.Name() -} - -func (target *Target) FullName() string { - return target.basePkg.FullName() -} - -func (target *Target) ShortName() string { - return filepath.Base(target.Name()) -} - -func (target *Target) Clone(newRepo *repo.Repo, newName string) *Target { - // Clone the target. - newTarget := *target - newTarget.basePkg = target.basePkg.Clone(newRepo, newName) - - // Insert the clone into the global target map. - GetTargets()[newTarget.FullName()] = &newTarget - - return &newTarget -} - -func (target *Target) resolvePackageName(name string) *pkg.LocalPackage { - dep, err := pkg.NewDependency(target.basePkg.Repo(), name) - if err != nil { - return nil - } - - pack, ok := project.GetProject().ResolveDependency(dep).(*pkg.LocalPackage) - if !ok { - return nil - } - - return pack -} - -func (target *Target) App() *pkg.LocalPackage { - return target.resolvePackageName(target.AppName) -} - -func (target *Target) Loader() *pkg.LocalPackage { - return target.resolvePackageName(target.LoaderName) -} - -func (target *Target) Bsp() *pkg.LocalPackage { - return target.resolvePackageName(target.BspName) -} - -func (target *Target) BinBasePath() string { - appPkg := target.App() - if appPkg == nil { - return "" - } - - return appPkg.BasePath() + "/bin/" + target.Name() + "/" + - appPkg.Name() -} - -func (target *Target) ElfPath() string { - return target.BinBasePath() + ".elf" -} - -func (target *Target) ImagePath() string { - return target.BinBasePath() + ".img" -} - -// Save the target's configuration elements -func (t *Target) Save() error { - if err := t.basePkg.Save(); err != nil { - return err - } - - dirpath := t.basePkg.BasePath() - filepath := dirpath + "/" + TARGET_FILENAME - file, err := os.Create(filepath) - if err != nil { - return util.NewNewtError(err.Error()) - } - defer file.Close() - - file.WriteString("### Target: " + t.Name() + "\n") - - keys := []string{} - for k, _ := range t.Vars { - keys = append(keys, k) - } - sort.Strings(keys) - - for _, k := range keys { - file.WriteString(k + ": " + yaml.EscapeString(t.Vars[k]) + "\n") - } - - if err := t.basePkg.SaveSyscfgVals(); err != nil { - return err - } - - return nil -} - -func buildTargetMap() error { - globalTargetMap = map[string]*Target{} - - packs := project.GetProject().PackagesOfType(pkg.PACKAGE_TYPE_TARGET) - for _, packItf := range packs { - pack := packItf.(*pkg.LocalPackage) - target, err := LoadTarget(pack) - if err != nil { - nerr := err.(*util.NewtError) - util.ErrorMessage(util.VERBOSITY_QUIET, - "Warning: failed to load target \"%s\": %s\n", pack.Name(), - nerr.Text) - } else { - globalTargetMap[pack.FullName()] = target - } - } - - return nil -} - -func ResetTargets() { - globalTargetMap = nil -} - -func GetTargets() map[string]*Target { - if globalTargetMap == nil { - err := buildTargetMap() - if err != nil { - panic(err.Error()) - } - } - - return globalTargetMap -} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/e31a7d31/newt/toolchain/compiler.go ---------------------------------------------------------------------- diff --git a/newt/toolchain/compiler.go b/newt/toolchain/compiler.go deleted file mode 100644 index d2e484c..0000000 --- a/newt/toolchain/compiler.go +++ /dev/null @@ -1,1286 +0,0 @@ -/** - * 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 toolchain - -import ( - "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" - "regexp" - "runtime" - "sort" - "strconv" - "strings" - "sync" - "time" - - log "github.com/Sirupsen/logrus" - - "mynewt.apache.org/newt/newt/newtutil" - "mynewt.apache.org/newt/newt/project" - "mynewt.apache.org/newt/newt/symbol" - "mynewt.apache.org/newt/util" - "mynewt.apache.org/newt/viper" -) - -const COMPILER_FILENAME string = "compiler.yml" - -const ( - COMPILER_TYPE_C = 0 - COMPILER_TYPE_ASM = 1 - COMPILER_TYPE_CPP = 2 - COMPILER_TYPE_ARCHIVE = 3 -) - -type CompilerInfo struct { - Includes []string - Cflags []string - Lflags []string - Aflags []string - IgnoreFiles []*regexp.Regexp - IgnoreDirs []*regexp.Regexp -} - -type Compiler struct { - objPathList map[string]bool - LinkerScripts []string - - // Needs to be locked whenever a mutable field in this struct is accessed - // during a build. Currently, objPathList is the only such member. - mutex *sync.Mutex - - depTracker DepTracker - ccPath string - cppPath string - asPath string - arPath string - odPath string - osPath string - ocPath string - ldResolveCircularDeps bool - ldMapFile bool - ldBinFile bool - baseDir string - srcDir string - dstDir string - - // The info to be applied during compilation. - info CompilerInfo - - // Info read from the compiler package itself. This is kept separate from - // the rest of the info because it has the lowest priority; it can only be - // added immediately before compiling beings. - lclInfo CompilerInfo - - // Indicates whether the local compiler info has been appended to the - // common info set. Ensures the local info only gets added once. - lclInfoAdded bool - - extraDeps []string -} - -type CompilerJob struct { - Filename string - Compiler *Compiler - CompilerType int -} - -func NewCompilerInfo() *CompilerInfo { - ci := &CompilerInfo{} - ci.Includes = []string{} - ci.Cflags = []string{} - ci.Lflags = []string{} - ci.Aflags = []string{} - ci.IgnoreFiles = []*regexp.Regexp{} - ci.IgnoreDirs = []*regexp.Regexp{} - - return ci -} - -// Extracts the base of a flag string. A flag base is used when detecting flag -// conflicts. If two flags have identicial bases, then they are in conflict. -func flagsBase(cflags string) string { - eqIdx := strings.IndexByte(cflags, '=') - if eqIdx == -1 { - return cflags - } else { - return cflags[:eqIdx] - } -} - -// Creates a map of flag bases to flag values, i.e., -// [flag-base] => flag -// -// This is used to make flag conflict detection more efficient. -func flagsMap(cflags []string) map[string]string { - hash := map[string]string{} - for _, cf := range cflags { - hash[flagsBase(cf)] = cf - } - - return hash -} - -// Appends a new set of flags to an original set. If a new flag conflicts with -// an original, the new flag is discarded. The assumption is that flags from -// higher priority packages get added first. -// -// This is not terribly efficient: it results in flag maps being generated -// repeatedly when they could be cached. Any inefficiencies here are probably -// negligible compared to the time spent compiling and linking. If this -// assumption turns out to be incorrect, we should cache the flag maps. -func addFlags(flagType string, orig []string, new []string) []string { - origMap := flagsMap(orig) - - combined := orig - for _, c := range new { - newBase := flagsBase(c) - origVal := origMap[newBase] - if origVal == "" { - // New flag; add it. - combined = append(combined, c) - } else { - // Flag already present from a higher priority package; discard the - // new one. - if origVal != c { - log.Debugf("Discarding %s %s in favor of %s", flagType, c, - origVal) - } - } - } - - 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) - ci.Lflags = addFlags("lflag", ci.Lflags, newCi.Lflags) - ci.Aflags = addFlags("aflag", ci.Aflags, newCi.Aflags) - ci.IgnoreFiles = append(ci.IgnoreFiles, newCi.IgnoreFiles...) - ci.IgnoreDirs = append(ci.IgnoreDirs, newCi.IgnoreDirs...) -} - -func NewCompiler(compilerDir string, dstDir string, - buildProfile string) (*Compiler, error) { - - c := &Compiler{ - mutex: &sync.Mutex{}, - objPathList: map[string]bool{}, - baseDir: project.GetProject().BasePath, - srcDir: "", - dstDir: dstDir, - extraDeps: []string{}, - } - - c.depTracker = NewDepTracker(c) - - util.StatusMessage(util.VERBOSITY_VERBOSE, - "Loading compiler %s, buildProfile %s\n", compilerDir, - buildProfile) - err := c.load(compilerDir, buildProfile) - if err != nil { - return nil, err - } - - return c, nil -} - -func loadFlags(v *viper.Viper, features map[string]bool, - key string) []string { - - flags := []string{} - - rawFlags := newtutil.GetStringSliceFeatures(v, features, key) - for _, rawFlag := range rawFlags { - if strings.HasPrefix(rawFlag, key) { - expandedFlags := newtutil.GetStringSliceFeatures(v, features, - rawFlag) - - flags = append(flags, expandedFlags...) - } else { - flags = append(flags, strings.Trim(rawFlag, "\n")) - } - } - - return flags -} - -func (c *Compiler) load(compilerDir string, buildProfile string) error { - v, err := util.ReadConfig(compilerDir, "compiler") - if err != nil { - return err - } - - features := map[string]bool{ - buildProfile: true, - strings.ToUpper(runtime.GOOS): true, - } - - c.ccPath = newtutil.GetStringFeatures(v, features, "compiler.path.cc") - c.cppPath = newtutil.GetStringFeatures(v, features, "compiler.path.cpp") - c.asPath = newtutil.GetStringFeatures(v, features, "compiler.path.as") - c.arPath = newtutil.GetStringFeatures(v, features, "compiler.path.archive") - c.odPath = newtutil.GetStringFeatures(v, features, "compiler.path.objdump") - c.osPath = newtutil.GetStringFeatures(v, features, "compiler.path.objsize") - c.ocPath = newtutil.GetStringFeatures(v, features, "compiler.path.objcopy") - - c.lclInfo.Cflags = loadFlags(v, features, "compiler.flags") - c.lclInfo.Lflags = loadFlags(v, features, "compiler.ld.flags") - c.lclInfo.Aflags = loadFlags(v, features, "compiler.as.flags") - - c.ldResolveCircularDeps, err = newtutil.GetBoolFeatures(v, features, - "compiler.ld.resolve_circular_deps") - if err != nil { - return err - } - - c.ldMapFile, err = newtutil.GetBoolFeatures(v, features, - "compiler.ld.mapfile") - if err != nil { - return err - } - - c.ldBinFile, err = newtutil.GetBoolFeaturesDflt(v, features, - "compiler.ld.binfile", true) - if err != nil { - return err - } - - if len(c.lclInfo.Cflags) == 0 { - // Assume no Cflags implies an unsupported build profile. - return util.FmtNewtError("Compiler doesn't support build profile "+ - "specified by target on this OS (build_profile=\"%s\" OS=\"%s\")", - buildProfile, runtime.GOOS) - } - - return nil -} - -func (c *Compiler) AddInfo(info *CompilerInfo) { - c.info.AddCompilerInfo(info) -} - -func (c *Compiler) DstDir() string { - return c.dstDir -} - -func (c *Compiler) SetSrcDir(srcDir string) { - c.srcDir = filepath.ToSlash(filepath.Clean(srcDir)) -} - -func (c *Compiler) AddDeps(depFilenames ...string) { - c.extraDeps = append(c.extraDeps, depFilenames...) -} - -// Skips compilation of the specified C or assembly file, but adds the name of -// the object file that would have been generated to the compiler's list of -// object files. This function is used when the object file is already up to -// date, so no compilation is necessary. The name of the object file should -// still be remembered so that it gets linked in to the final library or -// executable. -func (c *Compiler) SkipSourceFile(srcFile string) error { - objPath := c.dstFilePath(srcFile) + ".o" - - c.mutex.Lock() - c.objPathList[filepath.ToSlash(objPath)] = true - c.mutex.Unlock() - - // Update the dependency tracker with the object file's modification time. - // This is necessary later for determining if the library / executable - // needs to be rebuilt. - err := c.depTracker.ProcessFileTime(objPath) - if err != nil { - return err - } - - return nil -} - -// Generates a string consisting of all the necessary include path (-I) -// options. The result is sorted and contains no duplicate paths. -func (c *Compiler) includesStrings() []string { - if len(c.info.Includes) == 0 { - return nil - } - - includes := util.SortFields(c.info.Includes...) - - tokens := make([]string, len(includes)) - for i, s := range includes { - s = strings.TrimPrefix(filepath.ToSlash(filepath.Clean(s)), c.baseDir+"/") - tokens[i] = "-I" + s - } - - return tokens -} - -func (c *Compiler) cflagsStrings() []string { - cflags := util.SortFields(c.info.Cflags...) - return cflags -} - -func (c *Compiler) aflagsStrings() []string { - aflags := util.SortFields(c.info.Aflags...) - return aflags -} - -func (c *Compiler) lflagsStrings() []string { - lflags := util.SortFields(c.info.Lflags...) - return lflags -} - -func (c *Compiler) depsString() string { - extraDeps := util.SortFields(c.extraDeps...) - return strings.Join(extraDeps, " ") + "\n" -} - -func (c *Compiler) dstFilePath(srcPath string) string { - relSrcPath := strings.TrimPrefix(filepath.ToSlash(srcPath), c.baseDir+"/") - relDstPath := strings.TrimSuffix(relSrcPath, filepath.Ext(srcPath)) - dstPath := fmt.Sprintf("%s/%s", c.dstDir, relDstPath) - return dstPath -} - -// Calculates the command-line invocation necessary to compile the specified C -// or assembly file. -// -// @param file The filename of the source file to compile. -// @param compilerType One of the COMPILER_TYPE_[...] constants. -// -// @return (success) The command arguments. -func (c *Compiler) CompileFileCmd(file string, compilerType int) ( - []string, error) { - - objPath := c.dstFilePath(file) + ".o" - - var cmdName string - var flags []string - switch compilerType { - case COMPILER_TYPE_C: - cmdName = c.ccPath - flags = c.cflagsStrings() - case COMPILER_TYPE_ASM: - cmdName = c.asPath - - // Include both the compiler flags and the assembler flags. - // XXX: This is not great. We don't have a way of specifying compiler - // flags without also passing them to the assembler. - flags = append(c.cflagsStrings(), c.aflagsStrings()...) - case COMPILER_TYPE_CPP: - cmdName = c.cppPath - flags = c.cflagsStrings() - default: - return nil, util.NewNewtError("Unknown compiler type") - } - - srcPath := strings.TrimPrefix(file, c.baseDir+"/") - cmd := []string{cmdName} - cmd = append(cmd, flags...) - cmd = append(cmd, c.includesStrings()...) - cmd = append(cmd, []string{ - "-c", - "-o", - objPath, - srcPath, - }...) - - return cmd, nil -} - -// Generates a dependency Makefile (.d) for the specified source C file. -// -// @param file The name of the source file. -func (c *Compiler) GenDepsForFile(file string) error { - depPath := c.dstFilePath(file) + ".d" - depDir := filepath.Dir(depPath) - if util.NodeNotExist(depDir) { - os.MkdirAll(depDir, 0755) - } - - srcPath := strings.TrimPrefix(file, c.baseDir+"/") - cmd := []string{c.ccPath} - cmd = append(cmd, c.cflagsStrings()...) - cmd = append(cmd, c.includesStrings()...) - cmd = append(cmd, []string{"-MM", "-MG", srcPath}...) - - o, err := util.ShellCommandLimitDbgOutput(cmd, nil, 0) - if err != nil { - return err - } - - // Write the compiler output to a dependency file. - f, err := os.OpenFile(depPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666) - if err != nil { - return util.ChildNewtError(err) - } - defer f.Close() - - if _, err := f.Write(o); err != nil { - return util.ChildNewtError(err) - } - - // Append the extra dependencies (.yml files) to the .d file. - objFile := strings.TrimSuffix(file, filepath.Ext(file)) + ".o" - if _, err := f.WriteString(objFile + ": " + c.depsString()); err != nil { - return util.NewNewtError(err.Error()) - } - - return nil -} - -func serializeCommand(cmd []string) []byte { - // Use a newline as the separator rather than a space to disambiguate cases - // where arguments contain spaces. - return []byte(strings.Join(cmd, "\n")) -} - -// Writes a file containing the command-line invocation used to generate the -// specified file. The file that this function writes can be used later to -// determine if the set of compiler options has changed. -// -// @param dstFile The output file whose build invocation is being -// recorded. -// @param cmd The command strings to write. -func writeCommandFile(dstFile string, cmd []string) error { - cmdPath := dstFile + ".cmd" - content := serializeCommand(cmd) - err := ioutil.WriteFile(cmdPath, content, 0644) - if err != nil { - return err - } - - return nil -} - -// Adds the info from the compiler package to the common set if it hasn't -// already been added. The compiler package's info needs to be added last -// because the compiler is the lowest priority package. -func (c *Compiler) ensureLclInfoAdded() { - if !c.lclInfoAdded { - log.Debugf("Generating build flags for compiler") - c.AddInfo(&c.lclInfo) - c.lclInfoAdded = true - } -} - -// Compile the specified C or assembly file. -// -// @param file The filename of the source file to compile. -// @param compilerType One of the COMPILER_TYPE_[...] constants. -func (c *Compiler) CompileFile(file string, compilerType int) error { - objPath := c.dstFilePath(file) + ".o" - objDir := filepath.Dir(objPath) - if util.NodeNotExist(objDir) { - os.MkdirAll(objDir, 0755) - } - - c.mutex.Lock() - c.objPathList[filepath.ToSlash(objPath)] = true - c.mutex.Unlock() - - cmd, err := c.CompileFileCmd(file, compilerType) - if err != nil { - return err - } - - srcPath := strings.TrimPrefix(file, c.baseDir+"/") - switch compilerType { - case COMPILER_TYPE_C: - util.StatusMessage(util.VERBOSITY_DEFAULT, "Compiling %s\n", srcPath) - case COMPILER_TYPE_CPP: - util.StatusMessage(util.VERBOSITY_DEFAULT, "Compiling %s\n", srcPath) - case COMPILER_TYPE_ASM: - util.StatusMessage(util.VERBOSITY_DEFAULT, "Assembling %s\n", srcPath) - default: - return util.NewNewtError("Unknown compiler type") - } - - _, err = util.ShellCommand(cmd, nil) - if err != nil { - return err - } - - err = writeCommandFile(objPath, cmd) - if err != nil { - return err - } - - // Tell the dependency tracker that an object file was just rebuilt. - c.depTracker.MostRecent = time.Now() - - return nil -} - -func (c *Compiler) shouldIgnoreFile(file string) bool { - file = strings.TrimPrefix(file, c.srcDir) - for _, re := range c.info.IgnoreFiles { - if match := re.MatchString(file); match { - return true - } - } - - return false -} - -func compilerTypeToExts(compilerType int) ([]string, error) { - switch compilerType { - case COMPILER_TYPE_C: - return []string{"c"}, nil - case COMPILER_TYPE_ASM: - return []string{"s", "S"}, nil - case COMPILER_TYPE_CPP: - return []string{"cc", "cpp", "cxx"}, nil - case COMPILER_TYPE_ARCHIVE: - return []string{"a"}, nil - default: - return nil, util.NewNewtError("Wrong compiler type specified to " + - "compilerTypeToExts") - } -} - -// Compiles all C files matching the specified file glob. -func (c *Compiler) CompileC(filename string) error { - filename = filepath.ToSlash(filename) - - if c.shouldIgnoreFile(filename) { - log.Infof("Ignoring %s because package dictates it.", filename) - return nil - } - - compileRequired, err := c.depTracker.CompileRequired(filename, - COMPILER_TYPE_C) - if err != nil { - return err - } - if compileRequired { - err = c.CompileFile(filename, COMPILER_TYPE_C) - } else { - err = c.SkipSourceFile(filename) - } - if err != nil { - return err - } - - return nil -} - -// Compiles all CPP files -func (c *Compiler) CompileCpp(filename string) error { - filename = filepath.ToSlash(filename) - - if c.shouldIgnoreFile(filename) { - log.Infof("Ignoring %s because package dictates it.", filename) - return nil - } - - compileRequired, err := c.depTracker.CompileRequired(filename, - COMPILER_TYPE_CPP) - if err != nil { - return err - } - - if compileRequired { - err = c.CompileFile(filename, COMPILER_TYPE_CPP) - } else { - err = c.SkipSourceFile(filename) - } - - if err != nil { - return err - } - - return nil -} - -// Compiles all assembly files matching the specified file glob. -// -// @param match The file glob specifying which assembly files -// to compile. -func (c *Compiler) CompileAs(filename string) error { - filename = filepath.ToSlash(filename) - - if c.shouldIgnoreFile(filename) { - log.Infof("Ignoring %s because package dictates it.", filename) - return nil - } - - compileRequired, err := c.depTracker.CompileRequired(filename, - COMPILER_TYPE_ASM) - if err != nil { - return err - } - if compileRequired { - err = c.CompileFile(filename, COMPILER_TYPE_ASM) - } else { - err = c.SkipSourceFile(filename) - } - if err != nil { - return err - } - - return nil -} - -// Copies all archive files matching the specified file glob. -// -// @param match The file glob specifying which assembly files -// to compile. -func (c *Compiler) CopyArchive(filename string) error { - filename = filepath.ToSlash(filename) - - if c.shouldIgnoreFile(filename) { - log.Infof("Ignoring %s because package dictates it.", filename) - return nil - } - - tgtFile := c.dstFilePath(filename) + ".a" - copyRequired, err := c.depTracker.CopyRequired(filename) - if err != nil { - return err - } - if copyRequired { - err = util.CopyFile(filename, tgtFile) - util.StatusMessage(util.VERBOSITY_DEFAULT, "copying %s\n", - filepath.ToSlash(tgtFile)) - } - - if err != nil { - return err - } - - return nil -} - -func (c *Compiler) processEntry(node os.FileInfo, cType int, - ignDirs []string) ([]CompilerJob, error) { - - // check to see if we ignore this element - for _, dir := range ignDirs { - if dir == node.Name() { - return nil, nil - } - } - - // Check in the user specified ignore directories - for _, dir := range c.info.IgnoreDirs { - if dir.MatchString(node.Name()) { - return nil, nil - } - } - - // If not, recurse into the directory. Make the output directory - // structure mirror that of the source tree. - prevSrcDir := c.srcDir - prevDstDir := c.dstDir - - c.srcDir += "/" + node.Name() - c.dstDir += "/" + node.Name() - - entries, err := c.RecursiveCollectEntries(cType, ignDirs) - - // Restore the compiler destination directory now that the child - // directory has been fully built. - c.srcDir = prevSrcDir - c.dstDir = prevDstDir - - return entries, err -} - -func (c *Compiler) RecursiveCollectEntries(cType int, - ignDirs []string) ([]CompilerJob, error) { - - // Make sure the compiler package info is added to the global set. - c.ensureLclInfoAdded() - - if err := os.Chdir(c.baseDir); err != nil { - return nil, util.ChildNewtError(err) - } - - // Get a list of files in the current directory, and if they are a - // directory, and that directory is not in the ignDirs variable, then - // recurse into that directory and compile the files in there - - ls, err := ioutil.ReadDir(c.srcDir) - if err != nil { - return nil, util.NewNewtError(err.Error()) - } - - entries := []CompilerJob{} - for _, node := range ls { - if node.IsDir() { - subEntries, err := c.processEntry(node, cType, ignDirs) - if err != nil { - return nil, err - } - - entries = append(entries, subEntries...) - } - } - - exts, err := compilerTypeToExts(cType) - if err != nil { - return nil, err - } - - for _, ext := range exts { - files, _ := filepath.Glob(c.srcDir + "/*." + ext) - for _, file := range files { - entries = append(entries, CompilerJob{ - Filename: file, - Compiler: c, - CompilerType: cType, - }) - } - } - - return entries, nil -} - -func RunJob(record CompilerJob) error { - switch record.CompilerType { - case COMPILER_TYPE_C: - return record.Compiler.CompileC(record.Filename) - case COMPILER_TYPE_ASM: - return record.Compiler.CompileAs(record.Filename) - case COMPILER_TYPE_CPP: - return record.Compiler.CompileCpp(record.Filename) - case COMPILER_TYPE_ARCHIVE: - return record.Compiler.CopyArchive(record.Filename) - default: - return util.NewNewtError("Wrong compiler type specified to " + - "RunJob") - } -} - -func (c *Compiler) getObjFiles(baseObjFiles []string) []string { - c.mutex.Lock() - for objName, _ := range c.objPathList { - baseObjFiles = append(baseObjFiles, objName) - } - c.mutex.Unlock() - - sort.Strings(baseObjFiles) - return baseObjFiles -} - -// Calculates the command-line invocation necessary to link the specified elf -// file. -// -// @param dstFile The filename of the destination elf file to -// link. -// @param options Some build options specifying how the elf file -// gets generated. -// @param objFiles An array of the source .o and .a filenames. -// -// @return (success) The command tokens. -func (c *Compiler) CompileBinaryCmd(dstFile string, options map[string]bool, - objFiles []string, keepSymbols []string, elfLib string) []string { - - objList := c.getObjFiles(util.UniqueStrings(objFiles)) - - cmd := []string{ - c.ccPath, - "-o", - dstFile, - } - cmd = append(cmd, c.cflagsStrings()...) - - if elfLib != "" { - cmd = append(cmd, "-Wl,--just-symbols="+elfLib) - } - - if c.ldResolveCircularDeps { - cmd = append(cmd, "-Wl,--start-group") - cmd = append(cmd, objList...) - cmd = append(cmd, "-Wl,--end-group") - } else { - cmd = append(cmd, objList...) - } - - if keepSymbols != nil { - for _, name := range keepSymbols { - cmd = append(cmd, "-Wl,--undefined="+name) - } - } - - cmd = append(cmd, c.lflagsStrings()...) - - /* so we don't get multiple global definitions of the same vartiable */ - //cmd += " -Wl,--warn-common " - - for _, ls := range c.LinkerScripts { - cmd = append(cmd, "-T") - cmd = append(cmd, ls) - } - if options["mapFile"] { - cmd = append(cmd, "-Wl,-Map="+dstFile+".map") - } - - return cmd -} - -// Links the specified elf file. -// -// @param dstFile The filename of the destination elf file to -// link. -// @param options Some build options specifying how the elf file -// gets generated. -// @param objFiles An array of the source .o and .a filenames. -func (c *Compiler) CompileBinary(dstFile string, options map[string]bool, - objFiles []string, keepSymbols []string, elfLib string) error { - - // Make sure the compiler package info is added to the global set. - c.ensureLclInfoAdded() - - objList := c.getObjFiles(util.UniqueStrings(objFiles)) - - util.StatusMessage(util.VERBOSITY_DEFAULT, "Linking %s\n", dstFile) - util.StatusMessage(util.VERBOSITY_VERBOSE, "Linking %s with input files %s\n", - dstFile, objList) - - if elfLib != "" { - util.StatusMessage(util.VERBOSITY_VERBOSE, "Linking %s with rom image %s\n", - dstFile, elfLib) - } - - cmd := c.CompileBinaryCmd(dstFile, options, objFiles, keepSymbols, elfLib) - _, err := util.ShellCommand(cmd, nil) - if err != nil { - return err - } - - err = writeCommandFile(dstFile, cmd) - if err != nil { - return err - } - - return nil -} - -// Generates the following build artifacts: -// * lst file -// * map file -// * bin file -// -// @param elfFilename The filename of the elf file corresponding to -// the artifacts to be generated. -// @param options Some build options specifying which artifacts -// get generated. -func (c *Compiler) generateExtras(elfFilename string, - options map[string]bool) error { - - if options["binFile"] { - binFile := elfFilename + ".bin" - cmd := []string{ - c.ocPath, - "-R", - ".bss", - "-R", - ".bss.core", - "-R", - ".bss.core.nz", - "-O", - "binary", - elfFilename, - binFile, - } - _, err := util.ShellCommand(cmd, nil) - if err != nil { - return err - } - } - - if options["listFile"] { - listFile := elfFilename + ".lst" - f, err := os.OpenFile(listFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, - 0666) - if err != nil { - return util.NewNewtError(err.Error()) - } - defer f.Close() - - cmd := []string{ - c.odPath, - "-wxdS", - elfFilename, - } - o, err := util.ShellCommandLimitDbgOutput(cmd, nil, 0) - if err != nil { - // XXX: gobjdump appears to always crash. Until we get that sorted - // out, don't fail the link process if lst generation fails. - return nil - } - - if _, err := f.Write(o); err != nil { - return util.ChildNewtError(err) - } - - sects := []string{".text", ".rodata", ".data"} - for _, sect := range sects { - cmd := []string{ - c.odPath, - "-s", - "-j", - sect, - elfFilename, - } - o, err := util.ShellCommandLimitDbgOutput(cmd, nil, 0) - if err != nil { - if _, err := f.Write(o); err != nil { - return util.NewNewtError(err.Error()) - } - } - } - - cmd = []string{ - c.osPath, - elfFilename, - } - o, err = util.ShellCommandLimitDbgOutput(cmd, nil, 0) - if err != nil { - return err - } - if _, err := f.Write(o); err != nil { - return util.NewNewtError(err.Error()) - } - } - - return nil -} - -func (c *Compiler) PrintSize(elfFilename string) (string, error) { - cmd := []string{ - c.osPath, - elfFilename, - } - o, err := util.ShellCommand(cmd, nil) - if err != nil { - return "", err - } - return string(o), nil -} - -// Links the specified elf file and generates some associated artifacts (lst, -// bin, and map files). -// -// @param binFile The filename of the destination elf file to -// link. -// @param options Some build options specifying how the elf file -// gets generated. -// @param objFiles An array of the source .o and .a filenames. -func (c *Compiler) CompileElf(binFile string, objFiles []string, - keepSymbols []string, elfLib string) error { - options := map[string]bool{"mapFile": c.ldMapFile, - "listFile": true, "binFile": c.ldBinFile} - - // Make sure the compiler package info is added to the global set. - c.ensureLclInfoAdded() - - linkRequired, err := c.depTracker.LinkRequired(binFile, options, - objFiles, keepSymbols, elfLib) - if err != nil { - return err - } - if linkRequired { - if err := os.MkdirAll(filepath.Dir(binFile), 0755); err != nil { - return util.NewNewtError(err.Error()) - } - err := c.CompileBinary(binFile, options, objFiles, keepSymbols, elfLib) - if err != nil { - return err - } - } - - err = c.generateExtras(binFile, options) - if err != nil { - return err - } - - return nil -} - -func (c *Compiler) RenameSymbolsCmd( - sm *symbol.SymbolMap, libraryFile string, ext string) []string { - - cmd := []string{c.ocPath} - for s, _ := range *sm { - cmd = append(cmd, "--redefine-sym") - cmd = append(cmd, s+"="+s+ext) - } - - cmd = append(cmd, libraryFile) - return cmd -} - -func (c *Compiler) ParseLibraryCmd(libraryFile string) []string { - return []string{ - c.odPath, - "-t", - libraryFile, - } -} - -func (c *Compiler) CopySymbolsCmd(infile string, outfile string, sm *symbol.SymbolMap) []string { - - cmd := []string{c.ocPath, "-S"} - for symbol, _ := range *sm { - cmd = append(cmd, "-K") - cmd = append(cmd, symbol) - } - - cmd = append(cmd, infile) - cmd = append(cmd, outfile) - - return cmd -} - -// Calculates the command-line invocation necessary to archive the specified -// static library. -// -// @param archiveFile The filename of the library to archive. -// @param objFiles An array of the source .o filenames. -// -// @return The command string. -func (c *Compiler) CompileArchiveCmd(archiveFile string, - objFiles []string) []string { - - cmd := []string{ - c.arPath, - "rcs", - archiveFile, - } - cmd = append(cmd, c.getObjFiles(objFiles)...) - return cmd -} - -func linkerScriptFileName(archiveFile string) string { - ar_script_name := strings.TrimSuffix(archiveFile, filepath.Ext(archiveFile)) + "_ar.mri" - return ar_script_name -} - -/* this create a new library combining all of the other libraries */ -func createSplitArchiveLinkerFile(archiveFile string, - archFiles []string) error { - - /* create a name for this script */ - ar_script_name := linkerScriptFileName(archiveFile) - - // open the file and write out the script - f, err := os.OpenFile(ar_script_name, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, - 0666) - if err != nil { - return util.NewNewtError(err.Error()) - } - defer f.Close() - - if _, err := f.WriteString("CREATE " + archiveFile + "\n"); err != nil { - return util.NewNewtError(err.Error()) - } - - for _, arch := range archFiles { - if _, err := f.WriteString("ADDLIB " + arch + "\n"); err != nil { - return util.NewNewtError(err.Error()) - } - } - - if _, err := f.WriteString("SAVE\n"); err != nil { - return util.NewNewtError(err.Error()) - } - - if _, err := f.WriteString("END\n"); err != nil { - return util.NewNewtError(err.Error()) - } - - return nil -} - -// calculates the command-line invocation necessary to build a split all -// archive from the collection of archive files -func (c *Compiler) BuildSplitArchiveCmd(archiveFile string) string { - - str := c.arPath + " -M < " + linkerScriptFileName(archiveFile) - return str -} - -// Archives the specified static library. -// -// @param archiveFile The filename of the library to archive. -// @param objFiles An array of the source .o filenames. -func (c *Compiler) CompileArchive(archiveFile string) error { - objFiles := []string{} - - // Make sure the compiler package info is added to the global set. - c.ensureLclInfoAdded() - - arRequired, err := c.depTracker.ArchiveRequired(archiveFile, objFiles) - if err != nil { - return err - } - if !arRequired { - return nil - } - - if err := os.MkdirAll(filepath.Dir(archiveFile), 0755); err != nil { - return util.NewNewtError(err.Error()) - } - - // Delete the old archive, if it exists. - os.Remove(archiveFile) - - objList := c.getObjFiles([]string{}) - if objList == nil { - return nil - } - - if len(objList) == 0 { - util.StatusMessage(util.VERBOSITY_VERBOSE, - "Not archiving %s; no object files\n", archiveFile) - return nil - } - - util.StatusMessage(util.VERBOSITY_DEFAULT, "Archiving %s", - path.Base(archiveFile)) - util.StatusMessage(util.VERBOSITY_VERBOSE, " with object files %s", - strings.Join(objList, " ")) - util.StatusMessage(util.VERBOSITY_DEFAULT, "\n") - - if err != nil && !os.IsNotExist(err) { - return util.NewNewtError(err.Error()) - } - - cmd := c.CompileArchiveCmd(archiveFile, objFiles) - _, err = util.ShellCommand(cmd, nil) - if err != nil { - return err - } - - err = writeCommandFile(archiveFile, cmd) - if err != nil { - return err - } - - return nil -} - -func getParseRexeg() (error, *regexp.Regexp) { - r, err := regexp.Compile("^([0-9A-Fa-f]+)[\t ]+([lgu! ][w ][C ][W ][Ii ][Dd ][FfO ])[\t ]+([^\t\n\f\r ]+)[\t ]+([0-9a-fA-F]+)[\t ]([^\t\n\f\r ]+)") - - if err != nil { - return err, nil - } - - return nil, r -} - -/* This is a tricky thing to parse. Right now, I keep all the - * flags together and just store the offset, size, name and flags. -* 00012970 l .bss 00000000 _end -* 00011c60 l .init_array 00000000 __init_array_start -* 00011c60 l .init_array 00000000 __preinit_array_start -* 000084b0 g F .text 00000034 os_arch_start -* 00000000 g .debug_aranges 00000000 __HeapBase -* 00011c88 g O .data 00000008 g_os_task_list -* 000082cc g F .text 0000004c os_idle_task -* 000094e0 g F .text 0000002e .hidden __gnu_uldivmod_helper -* 00000000 g .svc_table 00000000 SVC_Count -* 000125e4 g O .bss 00000004 g_console_is_init -* 00009514 g F .text 0000029c .hidden __divdi3 -* 000085a8 g F .text 00000054 os_eventq_put -*/ -func ParseObjectLine(line string, r *regexp.Regexp) (error, *symbol.SymbolInfo) { - - answer := r.FindAllStringSubmatch(line, 11) - - if len(answer) == 0 { - return nil, nil - } - - data := answer[0] - - if len(data) != 6 { - util.StatusMessage(util.VERBOSITY_DEFAULT, - "Not enough content in object file line --- %s", line) - return nil, nil - } - - si := symbol.NewSymbolInfo() - - si.Name = data[5] - - v, err := strconv.ParseUint(data[1], 16, 32) - - if err != nil { - util.StatusMessage(util.VERBOSITY_DEFAULT, - "Could not convert location from object file line --- %s", line) - return nil, nil - } - - si.Loc = int(v) - - v, err = strconv.ParseUint(data[4], 16, 32) - - if err != nil { - util.StatusMessage(util.VERBOSITY_DEFAULT, - "Could not convert size form object file line --- %s", line) - return nil, nil - } - - si.Size = int(v) - si.Code = data[2] - si.Section = data[3] - - return nil, si -} - -func (c *Compiler) RenameSymbols(sm *symbol.SymbolMap, libraryFile string, ext string) error { - - cmd := c.RenameSymbolsCmd(sm, libraryFile, ext) - - _, err := util.ShellCommand(cmd, nil) - - return err -} - -func (c *Compiler) ParseLibrary(libraryFile string) (error, []byte) { - cmd := c.ParseLibraryCmd(libraryFile) - - out, err := util.ShellCommand(cmd, nil) - if err != nil { - return err, nil - } - return err, out -} - -func (c *Compiler) CopySymbols(infile string, outfile string, sm *symbol.SymbolMap) error { - cmd := c.CopySymbolsCmd(infile, outfile, sm) - - _, err := util.ShellCommand(cmd, nil) - if err != nil { - return err - } - return err -}
