github.com/ratrocket/u-root@v0.0.0-20180201221235-1cf9f48ee2cf/pkg/uroot/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 uroot
     6  
     7  import (
     8  	"fmt"
     9  	"log"
    10  	"path/filepath"
    11  
    12  	"github.com/u-root/u-root/pkg/golang"
    13  )
    14  
    15  // SourceBuild is an implementation of Build that compiles the Go toolchain
    16  // (go, compile, link, asm) and an init process. It includes source files for
    17  // packages listed in `opts.Packages` to build from scratch.
    18  func SourceBuild(opts BuildOpts) (ArchiveFiles, error) {
    19  	af := NewArchiveFiles()
    20  
    21  	if err := af.AddFile(filepath.Join(opts.Env.GOROOT, "pkg/include"), "go/pkg/include"); err != nil {
    22  		return ArchiveFiles{}, err
    23  	}
    24  
    25  	log.Printf("Collecting package files and dependencies...")
    26  	deps := make(map[string]struct{})
    27  	for _, pkg := range opts.Packages {
    28  		// Add high-level packages' src files to archive.
    29  		p := goListPkg(opts, pkg, &af)
    30  		if p == nil {
    31  			continue
    32  		}
    33  		for _, d := range p.Deps {
    34  			deps[d] = struct{}{}
    35  		}
    36  	}
    37  	// Add src files of dependencies to archive.
    38  	for dep := range deps {
    39  		goListPkg(opts, dep, &af)
    40  	}
    41  
    42  	// Add Go toolchain.
    43  	log.Printf("Building go toolchain...")
    44  	if err := buildToolchain(opts); err != nil {
    45  		return ArchiveFiles{}, err
    46  	}
    47  
    48  	// Build init.
    49  	if err := opts.Env.Build("github.com/u-root/u-root/cmds/init", filepath.Join(opts.TempDir, "init"), golang.BuildOpts{}); err != nil {
    50  		return ArchiveFiles{}, err
    51  	}
    52  
    53  	// Add Go toolchain and init to archive.
    54  	if err := af.AddFile(opts.TempDir, ""); err != nil {
    55  		return ArchiveFiles{}, err
    56  	}
    57  	return af, nil
    58  }
    59  
    60  // buildToolchain builds the needed Go toolchain binaries: go, compile, link,
    61  // asm.
    62  func buildToolchain(opts BuildOpts) error {
    63  	goBin := filepath.Join(opts.TempDir, "go/bin/go")
    64  	tcbo := golang.BuildOpts{
    65  		ExtraArgs: []string{"-tags", "cmd_go_bootstrap"},
    66  	}
    67  	if err := opts.Env.Build("cmd/go", goBin, tcbo); err != nil {
    68  		return err
    69  	}
    70  
    71  	toolDir := filepath.Join(opts.TempDir, fmt.Sprintf("go/pkg/tool/%v_%v", opts.Env.GOOS, opts.Env.GOARCH))
    72  	for _, pkg := range []string{"compile", "link", "asm"} {
    73  		c := filepath.Join(toolDir, pkg)
    74  		if err := opts.Env.Build(fmt.Sprintf("cmd/%s", pkg), c, golang.BuildOpts{}); err != nil {
    75  			return err
    76  		}
    77  	}
    78  	return nil
    79  }
    80  
    81  func goListPkg(opts BuildOpts, importPath string, out *ArchiveFiles) *golang.ListPackage {
    82  	p, err := opts.Env.Deps(importPath)
    83  	if err != nil {
    84  		log.Printf("Can't list Go dependencies for %v; ignoring.", importPath)
    85  		return nil
    86  	}
    87  
    88  	// Add Go files in this package to archive.
    89  	for _, file := range append(append(p.GoFiles, p.SFiles...), p.HFiles...) {
    90  		relPath := filepath.Join("src", p.ImportPath, file)
    91  		srcFile := filepath.Join(p.Root, relPath)
    92  		if p.Goroot {
    93  			out.AddFile(srcFile, filepath.Join("go", relPath))
    94  		} else {
    95  			out.AddFile(srcFile, relPath)
    96  		}
    97  	}
    98  	return p
    99  }