gopkg.in/hugelgupf/u-root.v9@v9.0.0-20180831063832-3f6f1057f09b/pkg/uroot/builder/source.go (about) 1 // Copyright 2015-2017 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package builder 6 7 import ( 8 "fmt" 9 "log" 10 "path" 11 "path/filepath" 12 13 "github.com/u-root/u-root/pkg/cpio" 14 "github.com/u-root/u-root/pkg/golang" 15 "github.com/u-root/u-root/pkg/uroot/initramfs" 16 ) 17 18 // SourceBuilder includes full source for Go commands in the initramfs. 19 // 20 // SourceBuilder is an implementation of Builder. 21 // 22 // It also includes the Go toolchain in the initramfs, and a tool called 23 // installcommand that can compile the other commands using symlinks. 24 // 25 // E.g. if "ls" is an included command, "ls" will be a symlink to 26 // "installcommand" in the initramfs, which uses argv[0] to figure out which 27 // command to compile. 28 type SourceBuilder struct{} 29 30 // DefaultBinaryDir implements Builder.DefaultBinaryDir. 31 // 32 // The initramfs default binary dir is buildbin. 33 func (SourceBuilder) DefaultBinaryDir() string { 34 return "buildbin" 35 } 36 37 // Build is an implementation of Builder.Build. 38 func (SourceBuilder) Build(af initramfs.Files, opts Opts) error { 39 // TODO: this is a failure to collect the correct dependencies. 40 if err := af.AddFile(filepath.Join(opts.Env.GOROOT, "pkg/include"), "go/pkg/include"); err != nil { 41 return err 42 } 43 44 var installcommand string 45 log.Printf("Collecting package files and dependencies...") 46 deps := make(map[string]struct{}) 47 for _, pkg := range opts.Packages { 48 name := path.Base(pkg) 49 if name == "installcommand" { 50 installcommand = pkg 51 } 52 53 // Add high-level packages' src files to archive. 54 p := goListPkg(opts, pkg, &af) 55 if p == nil { 56 continue 57 } 58 for _, d := range p.Deps { 59 deps[d] = struct{}{} 60 } 61 62 // Add a symlink to installcommand. This means source mode can 63 // work with any init. 64 if err := af.AddRecord(cpio.Symlink( 65 path.Join(opts.BinaryDir, name), 66 path.Join("/", opts.BinaryDir, "installcommand"))); err != nil { 67 return err 68 } 69 } 70 if len(installcommand) == 0 { 71 return fmt.Errorf("must include a version of installcommand in source mode") 72 } 73 74 // Add src files of dependencies to archive. 75 for dep := range deps { 76 goListPkg(opts, dep, &af) 77 } 78 79 // Add Go toolchain. 80 log.Printf("Building go toolchain...") 81 if err := buildToolchain(opts); err != nil { 82 return err 83 } 84 if err := opts.Env.Build(installcommand, filepath.Join(opts.TempDir, opts.BinaryDir, "installcommand"), golang.BuildOpts{}); err != nil { 85 return err 86 } 87 88 // Add Go toolchain and installcommand to archive. 89 return af.AddFile(opts.TempDir, "") 90 } 91 92 // buildToolchain builds the needed Go toolchain binaries: go, compile, link, 93 // asm. 94 func buildToolchain(opts Opts) error { 95 goBin := filepath.Join(opts.TempDir, "go/bin/go") 96 tcbo := golang.BuildOpts{ 97 ExtraArgs: []string{"-tags", "cmd_go_bootstrap"}, 98 } 99 if err := opts.Env.Build("cmd/go", goBin, tcbo); err != nil { 100 return err 101 } 102 103 toolDir := filepath.Join(opts.TempDir, fmt.Sprintf("go/pkg/tool/%v_%v", opts.Env.GOOS, opts.Env.GOARCH)) 104 for _, pkg := range []string{"compile", "link", "asm"} { 105 c := filepath.Join(toolDir, pkg) 106 if err := opts.Env.Build(fmt.Sprintf("cmd/%s", pkg), c, golang.BuildOpts{}); err != nil { 107 return err 108 } 109 } 110 return nil 111 } 112 113 func goListPkg(opts Opts, importPath string, out *initramfs.Files) *golang.ListPackage { 114 p, err := opts.Env.Deps(importPath) 115 if err != nil { 116 log.Printf("Can't list Go dependencies for %v; ignoring.", importPath) 117 return nil 118 } 119 120 // Add Go files in this package to archive. 121 for _, file := range append(append(p.GoFiles, p.SFiles...), p.HFiles...) { 122 relPath := filepath.Join("src", p.ImportPath, file) 123 srcFile := filepath.Join(p.Root, relPath) 124 if p.Goroot { 125 out.AddFile(srcFile, filepath.Join("go", relPath)) 126 } else { 127 out.AddFile(srcFile, relPath) 128 } 129 } 130 return p 131 }