gopkg.in/hugelgupf/u-root.v4@v4.0.0-20180831060141-1d761fb73d50/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 19 type SourceBuilder struct{} 20 21 // DefaultBinaryDir implements Builder.DefaultBinaryDir. 22 func (SourceBuilder) DefaultBinaryDir() string { 23 return "buildbin" 24 } 25 26 // Build is an implementation of Build that includes opts.Packages' full 27 // source in the initramfs. 28 // 29 // It then also includes the Go toolchain (go, compile, link, asm) and an init 30 // process that can compile other programs in the initramfs. 31 func (SourceBuilder) Build(af initramfs.Files, opts Opts) error { 32 // TODO: this is a failure to collect the correct dependencies. 33 if err := af.AddFile(filepath.Join(opts.Env.GOROOT, "pkg/include"), "go/pkg/include"); err != nil { 34 return err 35 } 36 37 var installcommand string 38 log.Printf("Collecting package files and dependencies...") 39 deps := make(map[string]struct{}) 40 for _, pkg := range opts.Packages { 41 name := path.Base(pkg) 42 if name == "installcommand" { 43 installcommand = pkg 44 } 45 46 // Add high-level packages' src files to archive. 47 p := goListPkg(opts, pkg, &af) 48 if p == nil { 49 continue 50 } 51 for _, d := range p.Deps { 52 deps[d] = struct{}{} 53 } 54 55 // Add a symlink to installcommand. This means source mode can 56 // work with any init. 57 if err := af.AddRecord(cpio.Symlink( 58 path.Join(opts.BinaryDir, name), 59 path.Join("/", opts.BinaryDir, "installcommand"))); err != nil { 60 return err 61 } 62 } 63 if len(installcommand) == 0 { 64 return fmt.Errorf("must include a version of installcommand in source mode") 65 } 66 67 // Add src files of dependencies to archive. 68 for dep := range deps { 69 goListPkg(opts, dep, &af) 70 } 71 72 // Add Go toolchain. 73 log.Printf("Building go toolchain...") 74 if err := buildToolchain(opts); err != nil { 75 return err 76 } 77 if err := opts.Env.Build(installcommand, filepath.Join(opts.TempDir, opts.BinaryDir, "installcommand"), golang.BuildOpts{}); err != nil { 78 return err 79 } 80 81 // Add Go toolchain and installcommand to archive. 82 return af.AddFile(opts.TempDir, "") 83 } 84 85 // buildToolchain builds the needed Go toolchain binaries: go, compile, link, 86 // asm. 87 func buildToolchain(opts Opts) error { 88 goBin := filepath.Join(opts.TempDir, "go/bin/go") 89 tcbo := golang.BuildOpts{ 90 ExtraArgs: []string{"-tags", "cmd_go_bootstrap"}, 91 } 92 if err := opts.Env.Build("cmd/go", goBin, tcbo); err != nil { 93 return err 94 } 95 96 toolDir := filepath.Join(opts.TempDir, fmt.Sprintf("go/pkg/tool/%v_%v", opts.Env.GOOS, opts.Env.GOARCH)) 97 for _, pkg := range []string{"compile", "link", "asm"} { 98 c := filepath.Join(toolDir, pkg) 99 if err := opts.Env.Build(fmt.Sprintf("cmd/%s", pkg), c, golang.BuildOpts{}); err != nil { 100 return err 101 } 102 } 103 return nil 104 } 105 106 func goListPkg(opts Opts, importPath string, out *initramfs.Files) *golang.ListPackage { 107 p, err := opts.Env.Deps(importPath) 108 if err != nil { 109 log.Printf("Can't list Go dependencies for %v; ignoring.", importPath) 110 return nil 111 } 112 113 // Add Go files in this package to archive. 114 for _, file := range append(append(p.GoFiles, p.SFiles...), p.HFiles...) { 115 relPath := filepath.Join("src", p.ImportPath, file) 116 srcFile := filepath.Join(p.Root, relPath) 117 if p.Goroot { 118 out.AddFile(srcFile, filepath.Join("go", relPath)) 119 } else { 120 out.AddFile(srcFile, relPath) 121 } 122 } 123 return p 124 }