blob: 532db09792fd5906c353e5ba3932863c4751a8e5 [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 (
"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() {
// Indicate that this version of newt supports the generated logcfg header.
t.InjectSetting("NEWT_FEATURE_LOGCFG", "1")
// Indicate to the apache-mynewt-core code that this version of newt
// supports the sysdown mechanism (generated package shutdown functions).
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")
}
// resolveTransientPkgs replaces packages in a slice with the packages they
// link to. It has no effect on non-transient packages.
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()
// When populating seed lists, resolve transient packages as a separate
// step (i.e., fill the list with the "Yml()" version of each package, then
// call `resolveTransientPkgs` on the list). This is done so that we can
// detect and warn the user if transient packages are being used.
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)
// For split images, inject the SPLIT_[...] settings into the
// corresponding app packages. This ensures that:
// * The app packages know they are part of a split image during
// dependency resolution.
// * The app source files receive "-DSPLIT_[...]=1" command line
// arguments during compilation.
t.loaderPkg.InjectedSettings()["SPLIT_LOADER"] = "1"
if t.appPkg != nil {
t.appPkg.InjectedSettings()["SPLIT_APPLICATION"] = "1"
}
// Inject the SPLIT_IMAGE setting into the entire target. All packages
// now know that they are part of a split image build.
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 {
// A few features are automatically supported when the test command is
// used:
// * TEST: lets packages know that this is a test app
// * SELFTEST: indicates that the "newt test" command is used;
// causes a package to define a main() function.
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
}
// Configure the basic set of environment variables in the current process.
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)
}
for _, line := range t.res.ExperimentalWarning() {
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
}
// Generate loader sysinit.
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
}
}
// Generate app sysinit.
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
}
// Generate loader sysinit.
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
}
}
// XXX: Generate loader sysdown.
// Generate app sysdown.
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
}
// Generate flash map.
if err := flashmap.EnsureFlashMapWritten(
t.bspPkg.FlashMap,
srcDir,
incDir,
pkg.ShortName(t.target.Package())); err != nil {
return err
}
return nil
}
// extraADirs returns a slice of extra directories that should be used at link
// time. .a files in these directores are used as input to the link (in
// addition to .a files produced by building packages).
func (t *TargetBuilder) extraADirs() []string {
return []string{
// Artifacts generated by pre-link user scripts.
UserPreLinkSrcDir(t.target.FullName()),
}
// Note: we don't include the pre-build source directory in this list. At
// compile time, newt copies .a files from package source directories to
// their respective binary directories. Since pre-link scripts run after
// compile time, this copy never happens for pre-link artifacts, so we need
// to tell newt where to look.
}
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
}
// Create directories where user scripts can write artifacts to incorporate
// into the build.
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 {
/* Tentatively link the app (using the normal single image linker
* script)
*/
if err := t.AppBuilder.TentativeLink(t.bspPkg.LinkerScripts,
t.extraADirs()); err != nil {
return err
}
/* rebuild the loader */
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
}
/* Tentatively link the loader */
if err := t.LoaderBuilder.TentativeLink(t.bspPkg.LinkerScripts,
t.extraADirs()); err != nil {
return err
}
/* re-link the loader with app dependencies */
err, commonPkgs, commonSyms := t.RelinkLoader()
if err != nil {
return err
}
/* The app can ignore these packages next time */
delete(commonPkgs, t.bspPkg.Name())
t.AppBuilder.RemovePackages(commonPkgs)
/* create the special elf to link the app against */
/* its just the elf with a set of symbols removed and renamed */
err = t.LoaderBuilder.buildRomElf(commonSyms)
if err != nil {
return err
}
/* set up the linker elf and linker script for the app */
t.AppBuilder.linkElf = t.LoaderBuilder.AppLinkerElfPath()
return nil
}
/// Generates a .c source file with public key information required by the
/// bootloader.
///
/// The input filename should be supplied by the user in the target.yml file,
/// using the `target.key_file` option. This file can be either a private key
/// in PEM format, an extracted public key in PEM format or a DER file.
///
/// To extract a PEM public key from the private key:
/// `openssl ec -in ec_pk.pem -pubout -out pubkey.pub`
/// `openssl rsa -in rsa_pk.pem -RSAPublicKey_out -out pubkey.pub`
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)
}()
// Execute the set of pre-build user scripts.
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
}
// Execute the set of pre-link user scripts.
if err := t.execPreLinkCmds(workDir); err != nil {
return err
}
/* Link the app. */
if err := t.AppBuilder.Link(linkerScripts, t.extraADirs()); err != nil {
return err
}
// Execute the set of post-build user scripts.
if err := t.execPostLinkCmds(workDir); err != nil {
return err
}
return nil
}
/*
* 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
*/
func (t *TargetBuilder) RelinkLoader() (error, map[string]bool,
*symbol.SymbolMap) {
/* fetch symbols from the elf and from the libraries themselves */
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
}
/* fetch the symbol list from the app temporary elf */
err, appElfSym := t.AppBuilder.ParseObjectElf(t.AppBuilder.AppTentativeElfPath())
if err != nil {
return err, nil, nil
}
/* extract the library symbols and elf symbols from the loader */
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
}
/* create the set of matching and non-matching symbols */
err, smMatch, smNomatch := symbol.IdenticalUnion(appLibSym,
loaderLibSym, true, false)
/* which packages are shared between the two */
commonPkgs := smMatch.Packages()
uncommonPkgs := smNomatch.Packages()
/* ensure that the loader and app packages are never shared */
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
}
/* for each symbol in the elf of the app, if that symbol is in
* a common package, keep that symbol in the loader */
preserveElf := symbol.NewSymbolMap()
/* go through each symbol in the app */
for _, elfsym := range *appElfSym {
name := elfsym.Name
if libsym, ok := (*appLibSym)[name]; ok {
if _, ok := commonPkgs[libsym.Bpkg]; ok {
/* if its not in the loader elf, add it as undefined */
if _, ok := (*loaderElfSym)[name]; !ok {
preserveElf.Add(elfsym)
}
}
}
}
/* re-link loader */
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
}
func (t *TargetBuilder) GetTarget() *target.Target {
return t.target
}
func (t *TargetBuilder) GetTestPkg() *pkg.LocalPackage {
return t.testPkg
}
func (t *TargetBuilder) InjectSetting(key string, value string) {
t.injectedSettings[key] = value
}
// Calculates the size of a single boot trailer. This is the amount of flash
// that must be reserved at the end of each image slot.
func (t *TargetBuilder) bootTrailerSize() int {
var minWriteSz int
entry, ok := t.res.Cfg.Settings["MCU_FLASH_MIN_WRITE_SIZE"]
if !ok {
util.StatusMessage(util.VERBOSITY_DEFAULT,
"* Warning: target does not define MCU_FLASH_MIN_WRITE_SIZE "+
"setting; assuming a value of 1.\n")
minWriteSz = 1
} else {
val, err := util.AtoiNoOct(entry.Value)
if err != nil {
util.StatusMessage(util.VERBOSITY_DEFAULT,
"* Warning: target specifies invalid non-integer "+
"MCU_FLASH_MIN_WRITE_SIZE setting; assuming a "+
"value of 1.\n")
minWriteSz = 1
} else {
minWriteSz = val
}
}
/* Mynewt boot trailer format:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ~ MAGIC (16 octets) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ~ ~
* ~ Swap status (128 * min-write-size * 3) ~
* ~ ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Copy done | 0xff padding (up to min-write-sz - 1) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Image OK | 0xff padding (up to min-write-sz - 1) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
tsize := 16 + // Magic.
128*minWriteSz*3 + // Swap status.
minWriteSz + // Copy done.
minWriteSz // Image Ok.
log.Debugf("Min-write-size=%d; boot-trailer-size=%d", minWriteSz, tsize)
return tsize
}
// Calculates the size of the largest image that can be written to each image
// slot.
func (t *TargetBuilder) MaxImgSizes() []int {
sz0 := t.bspPkg.FlashMap.Areas[flash.FLASH_AREA_NAME_IMAGE_0].Size
sz1 := t.bspPkg.FlashMap.Areas[flash.FLASH_AREA_NAME_IMAGE_1].Size
trailerSz := t.bootTrailerSize()
return []int{
sz0 - trailerSz,
sz1 - trailerSz,
}
}
func (t *TargetBuilder) CreateDepGraph() (DepGraph, error) {
if err := t.ensureResolved(); err != nil {
return nil, err
}
return depGraph(t.res.MasterSet)
}
func (t *TargetBuilder) CreateRevdepGraph() (DepGraph, error) {
if err := t.ensureResolved(); err != nil {
return nil, err
}
return revdepGraph(t.res.MasterSet)
}