func (t *TargetBuilder) RelinkLoader() (error, map[string]bool,
	*symbol.SymbolMap) {
	log.Debugf("Loader packages:")
	for _, rpkg := range t.LoaderBuilder.SortedRpkgs() {
		log.Debugf("    * %s", rpkg.Lpkg.Name())
	}
	log.Debugf("App packages:")
	for _, rpkg := range t.AppBuilder.SortedRpkgs() {
		log.Debugf("    * %s", rpkg.Lpkg.Name())
	}
	err, appLibSym := t.AppBuilder.ExtractSymbolInfo()
	if err != nil {
		return err, nil, nil
	}
	err, appElfSym := t.AppBuilder.ParseObjectElf(t.AppBuilder.AppTentativeElfPath())
	if err != nil {
		return err, nil, nil
	}
	err, loaderLibSym := t.LoaderBuilder.ExtractSymbolInfo()
	if err != nil {
		return err, nil, nil
	}
	err, loaderElfSym := t.LoaderBuilder.ParseObjectElf(
		t.LoaderBuilder.AppTentativeElfPath())
	if err != nil {
		return err, nil, nil
	}
	err, smMatch, smNomatch := symbol.IdenticalUnion(appLibSym,
		loaderLibSym, true, false)
	commonPkgs := smMatch.Packages()
	uncommonPkgs := smNomatch.Packages()
	delete(commonPkgs, t.AppBuilder.appPkg.rpkg.Lpkg.Name())
	uncommonPkgs[t.AppBuilder.appPkg.rpkg.Lpkg.Name()] = true
	ma := smMatch.FilterPkg(t.AppBuilder.appPkg.rpkg.Lpkg.Name())
	smMatch.RemoveMap(ma)
	delete(commonPkgs, t.LoaderBuilder.appPkg.rpkg.Lpkg.Name())
	uncommonPkgs[t.LoaderBuilder.appPkg.rpkg.Lpkg.Name()] = true
	ml := smMatch.FilterPkg(t.LoaderBuilder.appPkg.rpkg.Lpkg.Name())
	smMatch.RemoveMap(ml)
	util.StatusMessage(util.VERBOSITY_VERBOSE,
		"Putting %d symbols from %d packages into loader\n",
		len(*smMatch), len(commonPkgs))
	var badpkgs []string
	var symbolStr string
	for v, _ := range uncommonPkgs {
		if t.AppBuilder.appPkg != nil &&
			t.AppBuilder.appPkg.rpkg.Lpkg.Name() != v &&
			t.LoaderBuilder.appPkg != nil &&
			t.LoaderBuilder.appPkg.rpkg.Lpkg.Name() != v {
			trouble := smNomatch.FilterPkg(v)
			var found bool
			for _, sym := range *trouble {
				if !sym.IsLocal() {
					found = true
				}
			}
			if found {
				symbolStr = (*trouble).String("Non Matching Symbols")
				badpkgs = append(badpkgs, v)
				delete(commonPkgs, v)
			}
		}
	}
	if len(badpkgs) > 0 {
		errStr := fmt.Sprintf(
			"Common packages with different implementation\n %s\n",
			strings.Join(badpkgs, "\n "))
		errStr += symbolStr
		return util.NewNewtError(errStr), nil, nil
	}
	preserveElf := symbol.NewSymbolMap()
	for _, elfsym := range *appElfSym {
		name := elfsym.Name
		if libsym, ok := (*appLibSym)[name]; ok {
			if _, ok := commonPkgs[libsym.Bpkg]; ok {
				if _, ok := (*loaderElfSym)[name]; !ok {
					preserveElf.Add(elfsym)
				}
			}
		}
	}
	project.ResetDeps(t.LoaderList)
	util.StatusMessage(util.VERBOSITY_VERBOSE,
		"Migrating %d unused symbols into Loader\n", len(*preserveElf))
	err = t.LoaderBuilder.KeepLink(t.bspPkg.LinkerScripts, preserveElf,
		t.extraADirs())
	if err != nil {
		return err, nil, nil
	}
	return err, commonPkgs, smMatch
}
/*
This function re-links the loader adding symbols from libraries
shared with the app. Returns a list of the common packages shared
by the app and loader
package builder
import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"
	log "github.com/sirupsen/logrus"
	"github.com/apache/mynewt-artifact/flash"
	"github.com/apache/mynewt-artifact/sec"
	"mynewt.apache.org/newt/newt/flashmap"
	"mynewt.apache.org/newt/newt/interfaces"
	"mynewt.apache.org/newt/newt/pkg"
	"mynewt.apache.org/newt/newt/project"
	"mynewt.apache.org/newt/newt/resolve"
	"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"
)
type TargetBuilder struct {
	target      *target.Target
	bspPkg      *pkg.BspPackage
	compilerPkg *pkg.LocalPackage
	appPkg      *pkg.LocalPackage
	loaderPkg   *pkg.LocalPackage
	testPkg     *pkg.LocalPackage
	AppBuilder *Builder
	AppList    interfaces.PackageList
	LoaderBuilder *Builder
	LoaderList    interfaces.PackageList
	keyFile          string
	injectedSettings map[string]string
	res *resolve.Resolution
}
func NewTargetTester(target *target.Target,
	testPkg *pkg.LocalPackage) (*TargetBuilder, error) {
	if err := target.Validate(testPkg == nil); err != nil {
		return nil, err
	}
	bspPkg, err := pkg.NewBspPackage(target.Bsp())
	if err != nil {
		return nil, err
	}
	compilerPkg, err := project.GetProject().ResolvePackage(
		bspPkg.Repo(), bspPkg.CompilerName)
	if err != nil {
		return nil, err
	}
	t := &TargetBuilder{
		target:           target,
		bspPkg:           bspPkg,
		compilerPkg:      compilerPkg,
		appPkg:           target.App(),
		loaderPkg:        target.Loader(),
		keyFile:          target.KeyFile,
		testPkg:          testPkg,
		injectedSettings: map[string]string{},
	}
	return t, nil
}
func NewTargetBuilder(target *target.Target) (*TargetBuilder, error) {
	return NewTargetTester(target, nil)
}
func (t *TargetBuilder) BspPkg() *pkg.BspPackage {
	return t.bspPkg
}
func (t *TargetBuilder) NewCompiler(dstDir string, buildProfile string) (
	*toolchain.Compiler, error) {
	if buildProfile == "" {
		buildProfile = t.target.BuildProfile
	}
	c, err := toolchain.NewCompiler(
		t.compilerPkg.BasePath(), dstDir, buildProfile)
	return c, err
}
func (t *TargetBuilder) injectNewtSettings() {
	t.InjectSetting("NEWT_FEATURE_LOGCFG", "1")
	t.InjectSetting("NEWT_FEATURE_SYSDOWN", "1")
}
func (t *TargetBuilder) injectBuildSettings() {
	t.InjectSetting("ARCH_NAME", "\""+t.bspPkg.Arch+"\"")
	t.InjectSetting("ARCH_"+util.CIdentifier(t.bspPkg.Arch), "1")
	if t.appPkg != nil {
		appName := filepath.Base(t.appPkg.Name())
		t.InjectSetting("APP_NAME", "\""+appName+"\"")
		t.InjectSetting("APP_"+util.CIdentifier(appName), "1")
	}
	bspName := filepath.Base(t.bspPkg.Name())
	t.InjectSetting("BSP_NAME", "\""+bspName+"\"")
	t.InjectSetting("BSP_"+util.CIdentifier(bspName), "1")
	tgtName := filepath.Base(t.target.Name())
	t.InjectSetting("TARGET_NAME", "\""+tgtName+"\"")
	t.InjectSetting("TARGET_"+util.CIdentifier(tgtName), "1")
}
func (t *TargetBuilder) resolveTransientPkgs(lps []*pkg.LocalPackage) {
	for i, lp := range lps {
		resolved := t.target.ResolvePackageName(lp.FullName())
		if resolved != lp {
			resolve.LogTransientWarning(lp)
			lps[i] = resolved
		}
	}
}
func (t *TargetBuilder) ensureResolved() error {
	if t.res != nil {
		return nil
	}
	t.injectNewtSettings()
	t.injectBuildSettings()
	var loaderSeeds []*pkg.LocalPackage
	if t.loaderPkg != nil {
		loaderSeeds = []*pkg.LocalPackage{
			t.target.LoaderYml(),
			t.target.BspYml(),
			t.compilerPkg,
			t.target.Package(),
		}
		t.resolveTransientPkgs(loaderSeeds)
		t.loaderPkg.InjectedSettings()["SPLIT_LOADER"] = "1"
		if t.appPkg != nil {
			t.appPkg.InjectedSettings()["SPLIT_APPLICATION"] = "1"
		}
		t.InjectSetting("SPLIT_IMAGE", "1")
	}
	appSeeds := []*pkg.LocalPackage{
		t.target.BspYml(),
		t.compilerPkg,
		t.target.Package(),
	}
	t.resolveTransientPkgs(appSeeds)
	if t.appPkg != nil {
		appSeeds = append(appSeeds, t.target.AppYml())
	}
	if t.testPkg != nil {
		t.InjectSetting("TEST", "1")
		t.InjectSetting("SELFTEST", "1")
		appSeeds = append(appSeeds, t.testPkg)
	}
	var err error
	t.res, err = resolve.ResolveFull(
		loaderSeeds, appSeeds, t.injectedSettings, t.bspPkg.FlashMap)
	if err != nil {
		return err
	}
	env := BasicEnvVars("", t.bspPkg)
	keys := make([]string, 0, len(env))
	for k, _ := range env {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	log.Debugf("exporting environment variables:")
	for _, k := range keys {
		v := env[k]
		log.Debugf("    %s=%s", k, env[k])
		err := os.Setenv(k, v)
		if err != nil {
			return util.FmtNewtError(
				"failed to set env var %s=%s: %s", k, v, err.Error())
		}
	}
	return nil
}
func (t *TargetBuilder) Resolve() (*resolve.Resolution, error) {
	if err := t.ensureResolved(); err != nil {
		return nil, err
	}
	return t.res, nil
}
func (t *TargetBuilder) validateAndWriteCfg() error {
	if err := t.ensureResolved(); err != nil {
		return err
	}
	if errText := t.res.ErrorText(); errText != "" {
		return util.NewNewtError(errText)
	}
	warningText := strings.TrimSpace(t.res.WarningText())
	if warningText != "" {
		log.Debug(warningText)
	}
	for _, line := range t.res.DeprecatedWarning() {
		log.Warn(line)
	}
	incDir := GeneratedIncludeDir(t.target.FullName())
	srcDir := GeneratedSrcDir(t.target.FullName())
	if err := syscfg.EnsureWritten(t.res.Cfg, incDir); err != nil {
		return err
	}
	if err := t.res.LCfg.EnsureWritten(incDir); err != nil {
		return err
	}
	if t.res.LoaderSet != nil {
		lpkgs := resolve.RpkgSliceToLpkgSlice(t.res.LoaderSet.Rpkgs)
		if err := t.res.SysinitCfg.EnsureWritten(lpkgs, srcDir,
			pkg.ShortName(t.target.Package()), true); err != nil {
			return err
		}
	}
	lpkgs := resolve.RpkgSliceToLpkgSlice(t.res.AppSet.Rpkgs)
	if err := t.res.SysinitCfg.EnsureWritten(lpkgs, srcDir,
		pkg.ShortName(t.target.Package()), false); err != nil {
		return err
	}
	if t.res.LoaderSet != nil {
		lpkgs := resolve.RpkgSliceToLpkgSlice(t.res.LoaderSet.Rpkgs)
		if err := t.res.SysdownCfg.EnsureWritten(lpkgs, srcDir,
			pkg.ShortName(t.target.Package()), true); err != nil {
			return err
		}
	}
	lpkgs = resolve.RpkgSliceToLpkgSlice(t.res.AppSet.Rpkgs)
	if err := t.res.SysdownCfg.EnsureWritten(lpkgs, srcDir,
		pkg.ShortName(t.target.Package()), false); err != nil {
		return err
	}
	if err := flashmap.EnsureFlashMapWritten(
		t.bspPkg.FlashMap,
		srcDir,
		incDir,
		pkg.ShortName(t.target.Package())); err != nil {
		return err
	}
	return nil
}
func (t *TargetBuilder) extraADirs() []string {
	return []string{
		UserPreLinkSrcDir(t.target.FullName()),
	}
}
func (t *TargetBuilder) PrepBuild() error {
	if err := t.ensureResolved(); err != nil {
		return err
	}
	flashErrText := t.bspPkg.FlashMap.ErrorText()
	if flashErrText != "" {
		return util.NewNewtError(flashErrText)
	}
	if err := t.validateAndWriteCfg(); err != nil {
		return err
	}
	err := os.MkdirAll(UserPreBuildSrcDir(t.target.FullName()), 0755)
	if err != nil {
		return util.NewNewtError(err.Error())
	}
	err = os.MkdirAll(UserPreBuildIncludeDir(t.target.FullName()), 0755)
	if err != nil {
		return util.NewNewtError(err.Error())
	}
	err = os.MkdirAll(UserPreLinkSrcDir(t.target.FullName()), 0755)
	if err != nil {
		return util.NewNewtError(err.Error())
	}
	if t.res.LoaderSet != nil {
		t.LoaderBuilder, err = NewBuilder(t, BUILD_NAME_LOADER,
			t.res.LoaderSet.Rpkgs, t.res.ApiMap, t.res.Cfg)
		if err != nil {
			return err
		}
		if err := t.LoaderBuilder.PrepBuild(); err != nil {
			return err
		}
		loaderFlags := toolchain.NewCompilerInfo()
		loaderFlags.Cflags = append(loaderFlags.Cflags, "-DSPLIT_LOADER")
		t.LoaderBuilder.AddCompilerInfo(loaderFlags)
		t.LoaderList = project.ResetDeps(nil)
	}
	t.AppBuilder, err = NewBuilder(t, BUILD_NAME_APP, t.res.AppSet.Rpkgs,
		t.res.ApiMap, t.res.Cfg)
	if err != nil {
		return err
	}
	if err := t.AppBuilder.PrepBuild(); err != nil {
		return err
	}
	if t.res.LoaderSet != nil {
		appFlags := toolchain.NewCompilerInfo()
		appFlags.Cflags = append(appFlags.Cflags, "-DSPLIT_APPLICATION")
		t.AppBuilder.AddCompilerInfo(appFlags)
	}
	t.AppList = project.ResetDeps(nil)
	logDepInfo(t.res)
	return nil
}
func (t *TargetBuilder) buildLoader() error {
	if err := t.AppBuilder.TentativeLink(t.bspPkg.LinkerScripts,
		t.extraADirs()); err != nil {
		return err
	}
	project.ResetDeps(t.LoaderList)
	if err := t.bspPkg.Reload(t.LoaderBuilder.cfg.SettingValues()); err != nil {
		return err
	}
	if err := t.LoaderBuilder.Build(); err != nil {
		return err
	}
	if err := t.LoaderBuilder.TentativeLink(t.bspPkg.LinkerScripts,
		t.extraADirs()); err != nil {
		return err
	}
	err, commonPkgs, commonSyms := t.RelinkLoader()
	if err != nil {
		return err
	}
	delete(commonPkgs, t.bspPkg.Name())
	t.AppBuilder.RemovePackages(commonPkgs)
	err = t.LoaderBuilder.buildRomElf(commonSyms)
	if err != nil {
		return err
	}
	t.AppBuilder.linkElf = t.LoaderBuilder.AppLinkerElfPath()
	return nil
}
func (t *TargetBuilder) autogenKeys() error {
	keyBytes, err := ioutil.ReadFile(t.keyFile)
	if err != nil {
		return util.NewNewtError(fmt.Sprintf("Error reading key file: %s", err))
	}
	var pubKey sec.PubSignKey
	privKey, err := sec.ParsePrivSignKey(keyBytes)
	if err != nil {
		pubKey, err = sec.ParsePubSignKey(keyBytes)
		if err != nil {
			return err
		}
	} else {
		pubKey = privKey.PubKey()
	}
	pubBytes, err := pubKey.Bytes()
	if err != nil {
		return err
	}
	srcDir := GeneratedSrcDir(t.target.FullName())
	f, _ := os.Create(srcDir + "/pubkey-autogen.c")
	w := bufio.NewWriter(f)
	fmt.Fprintln(w, "/* Autogenerated, do not edit. */")
	fmt.Fprintln(w, "#include <bootutil/sign_key.h>")
	fmt.Fprintf(w, "const unsigned char key[] = {")
	for count, b := range pubBytes {
		if count%8 == 0 {
			fmt.Fprintf(w, "\n    ")
		} else {
			fmt.Fprintf(w, " ")
		}
		fmt.Fprintf(w, "0x%02x,", b)
	}
	fmt.Fprintf(w, "\n};\n")
	fmt.Fprintf(w, "const unsigned int key_len = %v;\n", len(pubBytes))
	fmt.Fprintln(w, "const struct bootutil_key bootutil_keys[] = {")
	fmt.Fprintln(w, "    [0] = {")
	fmt.Fprintln(w, "        .key = key,")
	fmt.Fprintln(w, "        .len = &key_len,")
	fmt.Fprintln(w, "    },")
	fmt.Fprintln(w, "};")
	fmt.Fprintln(w, "const int bootutil_key_cnt = 1;")
	w.Flush()
	return nil
}
func (t *TargetBuilder) Build() error {
	if err := t.PrepBuild(); err != nil {
		return err
	}
	project.ResetDeps(t.AppList)
	if err := t.bspPkg.Reload(t.AppBuilder.cfg.SettingValues()); err != nil {
		return err
	}
	if t.keyFile != "" {
		err := t.autogenKeys()
		if err != nil {
			return err
		}
	}
	workDir, err := makeUserWorkDir()
	if err != nil {
		return err
	}
	defer func() {
		log.Debugf("removing user work dir: %s", workDir)
		os.RemoveAll(workDir)
	}()
	if err := t.execPreBuildCmds(workDir); err != nil {
		return err
	}
	if err := t.AppBuilder.Build(); err != nil {
		return err
	}
	var linkerScripts []string
	if t.LoaderBuilder == nil {
		linkerScripts = t.bspPkg.LinkerScripts
	} else {
		if err := t.buildLoader(); err != nil {
			return err
		}
		linkerScripts = t.bspPkg.Part2LinkerScripts
	}
	if err := t.execPreLinkCmds(workDir); err != nil {
		return err
	}
	if err := t.AppBuilder.Link(linkerScripts, t.extraADirs()); err != nil {
		return err
	}
	if err := t.execPostLinkCmds(workDir); err != nil {
		return err
	}
	return nil
}