blob: 599cec37767ab94d9b0cca1c18a1d14a830751b2 [file] [log] [blame]
/**
* 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 builder
import (
"bytes"
"sort"
"strconv"
"strings"
"github.com/kardianos/osext"
log "github.com/sirupsen/logrus"
"mynewt.apache.org/newt/newt/parse"
"mynewt.apache.org/newt/newt/pkg"
"mynewt.apache.org/newt/newt/project"
"mynewt.apache.org/newt/newt/resolve"
"mynewt.apache.org/newt/newt/toolchain"
"mynewt.apache.org/newt/util"
)
func TestTargetName(testPkgName string) string {
return strings.Replace(testPkgName, "/", "_", -1)
}
// FeatureString converts a syscfg map to a string. The string is a
// space-separate list of "enabled" settings.
func FeatureString(settings map[string]string) string {
var buffer bytes.Buffer
featureSlice := make([]string, 0, len(settings))
for k, v := range settings {
if parse.ValueIsTrue(v) {
featureSlice = append(featureSlice, k)
}
}
sort.Strings(featureSlice)
for i, feature := range featureSlice {
if i != 0 {
buffer.WriteString(" ")
}
buffer.WriteString(feature)
}
return buffer.String()
}
type bpkgSorter struct {
bpkgs []*BuildPackage
}
func (b bpkgSorter) Len() int {
return len(b.bpkgs)
}
func (b bpkgSorter) Swap(i, j int) {
b.bpkgs[i], b.bpkgs[j] = b.bpkgs[j], b.bpkgs[i]
}
func (b bpkgSorter) Less(i, j int) bool {
return b.bpkgs[i].rpkg.Lpkg.Name() < b.bpkgs[j].rpkg.Lpkg.Name()
}
func (b *Builder) sortedBuildPackages() []*BuildPackage {
sorter := bpkgSorter{
bpkgs: make([]*BuildPackage, 0, len(b.PkgMap)),
}
for _, bpkg := range b.PkgMap {
sorter.bpkgs = append(sorter.bpkgs, bpkg)
}
sort.Sort(sorter)
return sorter.bpkgs
}
func (b *Builder) SortedRpkgs() []*resolve.ResolvePackage {
bpkgs := b.sortedBuildPackages()
rpkgs := make([]*resolve.ResolvePackage, len(bpkgs), len(bpkgs))
for i, bpkg := range bpkgs {
rpkgs[i] = bpkg.rpkg
}
return rpkgs
}
func logDepInfo(res *resolve.Resolution) {
// Log API set.
apis := []string{}
for api, _ := range res.ApiMap {
apis = append(apis, api)
}
sort.Strings(apis)
log.Debugf("API set:")
for _, api := range apis {
rpkg := res.ApiMap[api]
log.Debugf(" * " + api + " (" + rpkg.Lpkg.FullName() + ")")
}
// Log dependency graph.
dg, err := depGraph(res.MasterSet)
if err != nil {
log.Debugf("Error while constructing dependency graph: %s\n",
err.Error())
} else {
log.Debugf("%s", DepGraphText(dg))
}
// Log reverse dependency graph.
rdg, err := revdepGraph(res.MasterSet)
if err != nil {
log.Debugf("Error while constructing reverse dependency graph: %s\n",
err.Error())
} else {
log.Debugf("%s", RevdepGraphText(rdg))
}
}
// binBasePath calculates the relative path of the "application binary"
// directory. Examples:
// * bin/targets/my_blinky_sim/app
// * bin/targets/splitty-nrf52dk/loader
func (b *Builder) binBasePath() (string, error) {
var rawPath string
if b.appPkg != nil {
rawPath = b.AppBinBasePath()
} else if b.testPkg != nil {
rawPath = b.TestExePath()
} else {
return "", util.NewNewtError("no app or test package specified")
}
// Convert the binary path from absolute to relative. This is required for
// Windows compatibility.
return util.TryRelPath(rawPath), nil
}
// BasicEnvVars calculates the basic set of environment variables passed to all
// external scripts. `binBase` is the result of calling `binBasePath()`, or ""
// if you don't need the "BIN_BASENAME" setting.
func BasicEnvVars(binBase string, bspPkg *pkg.BspPackage) map[string]string {
coreRepo := project.GetProject().FindRepo("apache-mynewt-core")
bspPath := bspPkg.BasePath()
newtPath, _ := osext.Executable()
m := map[string]string{
"CORE_PATH": coreRepo.Path(),
"BSP_PATH": bspPath,
"BIN_ROOT": BinRoot(),
"MYNEWT_PROJECT_ROOT": ProjectRoot(),
"MYNEWT_NEWT_PATH": newtPath,
}
if binBase != "" {
m["BIN_BASENAME"] = binBase
}
return m
}
func ToolchainEnvVars(c *toolchain.Compiler) map[string]string {
return map[string]string{
"MYNEWT_AR_PATH": c.GetArPath(),
"MYNEWT_AS_PATH": c.GetAsPath(),
"MYNEWT_CC_PATH": c.GetCcPath(),
"MYNEWT_CPP_PATH": c.GetCppPath(),
"MYNEWT_OBJCOPY_PATH": c.GetObjcopyPath(),
"MYNEWT_OBJDUMP_PATH": c.GetObjdumpPath(),
"MYNEWT_SIZE_PATH": c.GetSizePath(),
}
}
// SettingsEnvVars calculates the syscfg set of environment variables required
// by image loading scripts.
func SettingsEnvVars(settings map[string]string) map[string]string {
env := map[string]string{}
// Add all syscfg settings to the environment with the MYNEWT_VAL_ prefix.
for k, v := range settings {
env["MYNEWT_VAL_"+k] = v
}
if parse.ValueIsTrue(settings["BOOT_LOADER"]) {
env["BOOT_LOADER"] = "1"
}
env["FEATURES"] = FeatureString(settings)
return env
}
// SlotEnvVars calculates the image-slot set of environment variables required
// by image loading scripts. Pass a negative `imageSlot` value if the target
// is a boot loader.
func SlotEnvVars(bspPkg *pkg.BspPackage,
imageSlot int) (map[string]string, error) {
env := map[string]string{}
var flashTargetArea string
if imageSlot < 0 {
flashTargetArea = "FLASH_AREA_BOOTLOADER"
} else {
env["IMAGE_SLOT"] = strconv.Itoa(imageSlot)
switch imageSlot {
case 0:
flashTargetArea = "FLASH_AREA_IMAGE_0"
case 1:
flashTargetArea = "FLASH_AREA_IMAGE_1"
default:
return nil, util.FmtNewtError(
"invalid image slot: have=%d want=0or1", imageSlot)
}
}
tgtArea := bspPkg.FlashMap.Areas[flashTargetArea]
if tgtArea.Name == "" {
return nil, util.FmtNewtError(
"No flash target area %s", flashTargetArea)
}
env["FLASH_OFFSET"] = "0x" + strconv.FormatInt(int64(tgtArea.Offset), 16)
env["FLASH_AREA_SIZE"] = "0x" + strconv.FormatInt(int64(tgtArea.Size), 16)
return env, nil
}
type UserEnvParams struct {
Lpkg *pkg.LocalPackage
TargetName string // Short name
BuildProfile string
AppName string
BuildName string // "app" or "loader"
UserSrcDir string // "" if none
UserIncDir string // "" if none
WorkDir string
}
// UserEnvVars calculates the set of environment variables required by external
// user scripts.
func UserEnvVars(params UserEnvParams) map[string]string {
m := map[string]string{}
m["MYNEWT_APP_BIN_DIR"] = FileBinDir(
params.TargetName, params.BuildName, params.AppName)
m["MYNEWT_PKG_BIN_ARCHIVE"] = ArchivePath(
params.TargetName, params.BuildName, params.Lpkg.FullName(),
params.Lpkg.Type())
m["MYNEWT_PKG_BIN_DIR"] = PkgBinDir(
params.TargetName, params.BuildName, params.Lpkg.FullName(),
params.Lpkg.Type())
m["MYNEWT_PKG_NAME"] = params.Lpkg.FullName()
m["MYNEWT_USER_WORK_DIR"] = params.WorkDir
if params.UserSrcDir != "" {
m["MYNEWT_USER_SRC_DIR"] = params.UserSrcDir
}
if params.UserIncDir != "" {
m["MYNEWT_USER_INCLUDE_DIR"] = params.UserIncDir
}
m["MYNEWT_BUILD_PROFILE"] = params.BuildProfile
return m
}
// EnvVars calculates the full set of environment variables passed to external
// scripts.
func (b *Builder) EnvVars(imageSlot int) (map[string]string, error) {
bspPkg := b.targetBuilder.bspPkg
settings := b.cfg.SettingValues()
binBasePath, err := b.binBasePath()
if err != nil {
return nil, err
}
// Calculate all three sets of environment variables: basic, settings, and
// slot. Then merge the three sets into one.
env := BasicEnvVars(binBasePath, bspPkg)
setEnv := SettingsEnvVars(settings)
if parse.ValueIsTrue(settings["BOOT_LOADER"]) {
imageSlot = -1
}
slotEnv, err := SlotEnvVars(bspPkg, imageSlot)
if err != nil {
return nil, err
}
for k, v := range setEnv {
env[k] = v
}
for k, v := range slotEnv {
env[k] = v
}
env["MYNEWT_INCLUDE_PATH"] = strings.Join(b.compilerInfo.Includes, ":")
env["MYNEWT_CFLAGS"] = strings.Join(b.compilerInfo.Cflags, " ")
pkgNames := []string{}
for _, p := range b.PkgMap {
pkgNames = append(pkgNames, p.rpkg.Lpkg.FullName())
}
sort.Strings(pkgNames)
env["MYNEWT_PACKAGES"] = strings.Join(pkgNames, ":")
return env, nil
}