github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/uroot/builder/binary.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 "os" 10 "path/filepath" 11 "sync" 12 13 gbbgolang "github.com/u-root/gobusybox/src/pkg/golang" 14 "github.com/mvdan/u-root-coreutils/pkg/ulog" 15 "github.com/mvdan/u-root-coreutils/pkg/uroot/initramfs" 16 "golang.org/x/tools/go/packages" 17 ) 18 19 func lookupPkgs(env gbbgolang.Environ, dir string, patterns ...string) ([]*packages.Package, error) { 20 cfg := &packages.Config{ 21 Mode: packages.NeedName | packages.NeedFiles, 22 Env: append(os.Environ(), env.Env()...), 23 Dir: dir, 24 } 25 return packages.Load(cfg, patterns...) 26 } 27 28 func dirFor(env gbbgolang.Environ, pkg string) (string, error) { 29 pkgs, err := lookupPkgs(env, "", pkg) 30 if err != nil { 31 return "", fmt.Errorf("failed to look up package %q: %v", pkg, err) 32 } 33 34 // One directory = one package in standard Go, so 35 // finding the first file's parent directory should 36 // find us the package directory. 37 var dir string 38 for _, p := range pkgs { 39 if len(p.GoFiles) > 0 { 40 dir = filepath.Dir(p.GoFiles[0]) 41 } 42 } 43 if dir == "" { 44 return "", fmt.Errorf("could not find package directory for %q", pkg) 45 } 46 return dir, nil 47 } 48 49 // BinaryBuilder builds each Go command as a separate binary. 50 // 51 // BinaryBuilder is an implementation of Builder. 52 type BinaryBuilder struct{} 53 54 // DefaultBinaryDir implements Builder.DefaultBinaryDir. 55 // 56 // "bin" is the default initramfs binary directory for these binaries. 57 func (BinaryBuilder) DefaultBinaryDir() string { 58 return "bin" 59 } 60 61 // Build implements Builder.Build. 62 func (BinaryBuilder) Build(l ulog.Logger, af *initramfs.Files, opts Opts) error { 63 result := make(chan error, len(opts.Packages)) 64 65 var wg sync.WaitGroup 66 for _, pkg := range opts.Packages { 67 wg.Add(1) 68 go func(p string) { 69 defer wg.Done() 70 dir, err := dirFor(opts.Env, p) 71 if err != nil { 72 result <- err 73 return 74 } 75 result <- opts.Env.BuildDir( 76 dir, 77 filepath.Join(opts.TempDir, opts.BinaryDir, filepath.Base(p)), 78 opts.BuildOpts) 79 }(pkg) 80 } 81 82 wg.Wait() 83 close(result) 84 85 for err := range result { 86 if err != nil { 87 return err 88 } 89 } 90 91 // Add bin directory to archive. 92 return af.AddFile(opts.TempDir, "") 93 }