builder

package
v2.0.0-...-3f8fdb0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 31, 2018 License: BSD-3-Clause Imports: 23 Imported by: 0

README

Go Busybox

bb.go in this package implements a Go source-to-source transformation on pure Go code (no cgo).

This AST transformation does the following:

  • Takes a Go command's source files and rewrites them into Go package files without global side effects.
  • Writes a main.go file with a main() that calls into the appropriate Go command package based on argv[0].

This allows you to take two Go commands, such as Go implementations of sl and cowsay and compile them into one binary.

Which command is invoked is determined by argv[0] or argv[1] if argv[0] is not recognized. Let's say bb is the compiled binary; the following are equivalent invocations of sl and cowsay:

# Make a symlink sl -> bb
ln -s bb sl
./sl -l

# Make a symlink cowsay -> bb
ln -s bb cowsay
./cowsay Haha
./bb sl -l
./bb cowsay Haha

AST Transformation

Principally, the AST transformation moves all global side-effects into callable package functions. E.g. main becomes Main, each init becomes InitN, and global variable assignments are moved into their own InitN.

Then, these Main and Init functions can be registered with a global map of commands by name and used when called upon.

Let's say a command github.com/org/repo/cmds/sl contains the following main.go:

package main

import (
  "flag"
  "log"
)

var name = flag.String("name", "", "Gimme name")

func init() {
  log.Printf("init")
}

func main() {
  log.Printf("train")
}

This would be rewritten to be:

package sl // based on the directory name or bazel-rule go_binary name

import (
  "flag"
  "log"

  // This package holds the global map of commands.
  "github.com/u-root/u-root/pkg/bb"
)

// Type has to be inferred through type checking.
var name string

func Init0() {
  log.Printf("init")
}

func Init1() {
  name = flag.String("name", "", "Gimme name")
}

func Init() {
  // Order is determined by go/types.Info.InitOrder.
  Init0()
  Init1()
}

func Main() {
  log.Printf("main")
}

func init() {
  // Register `sl` as a command.
  bb.Register("sl", Init, Main)
}
Shortcomings
  • If there is already a function Main or InitN for some N, there may be a compilation error.
  • Any packages imported by commands may still have global side-effects affecting other commands. Done properly, we would have to rewrite all non-standard-library packages as well as commands. This has not been necessary to implement so far. It would likely be necessary if two different imported packages register the same flag unconditionally globally.

Generated main

The main file can be generated based on any template Go files, but the default looks something like the following:

import (
  "os"

  "github.com/u-root/u-root/pkg/bb"

  // Side-effect import registers command with bb.
  _ "github.com/org/repo/cmds/generated/sl"
)

func main() {
  bb.Run(os.Argv[0])
}

The default template will use argv[1] if argv[0] is not in the map.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Builders = map[string]Builder{
	"bb":     BBBuilder{},
	"source": SourceBuilder{},
	"binary": BinaryBuilder{},
}

Functions

func BuildBusybox

func BuildBusybox(env golang.Environ, pkgs []string, binaryPath string) error

BuildBusybox builds a busybox of the given Go packages.

pkgs is a list of Go import paths. If nil is returned, binaryPath will hold the busybox-style binary.

func CreateBBMainSource

func CreateBBMainSource(fset *token.FileSet, astp *ast.Package, pkgs []string, destDir string) error

CreateBBMainSource creates a bb Go command that imports all given pkgs.

p must be the bb template.

  • For each pkg in pkgs, add import _ "pkg" to astp's first file.
  • Write source file out to destDir.

func ParseAST

func ParseAST(p *build.Package) (*token.FileSet, *ast.Package, error)

ParseAST parses p's package files into an AST.

func RewritePackage

func RewritePackage(env golang.Environ, pkgPath, destDir, bbImportPath string, importer types.Importer) error

RewritePackage rewrites pkgPath to be bb-mode compatible, where destDir is the file system destination of the written files and bbImportPath is the Go import path of the bb package to register with.

Types

type BBBuilder

type BBBuilder struct{}

BBBuilder is an implementation of Builder that compiles many Go commands into one busybox-style binary.

func (BBBuilder) Build

func (BBBuilder) Build(af initramfs.Files, opts Opts) error

Build is an implementation of uroot.Builder.Build for a busybox-like initramfs.

Build rewrites the source files of the packages given to create one busybox-like binary containing all commands in opts.Packages.

See pkg/uroot/README.md for a detailed explanation of busybox mode.

func (BBBuilder) DefaultBinaryDir

func (BBBuilder) DefaultBinaryDir() string

type BinaryBuilder

type BinaryBuilder struct{}

func (BinaryBuilder) Build

func (BinaryBuilder) Build(af initramfs.Files, opts Opts) error

Build builds all given packages as separate binaries and includes them in the archive.

func (BinaryBuilder) DefaultBinaryDir

func (BinaryBuilder) DefaultBinaryDir() string

type Builder

type Builder interface {
	// Build uses the given options to build Go packages and adds its files
	// to be included in the initramfs to the given ArchiveFiles.
	Build(initramfs.Files, Opts) error

	// DefaultBinaryDir is the initramfs' default directory for binaries
	// built using this builder.
	DefaultBinaryDir() string
}

Builder builds Go packages and adds the binaries to an initramfs.

The resulting files need not be binaries per se, but exec'ing the resulting file should result in the Go program being executed.

func GetBuilder

func GetBuilder(name string) (Builder, error)

GetBuilder returns the Build function for the named build mode.

type Opts

type Opts struct {
	// Env is the Go compiler environment.
	Env golang.Environ

	// Packages are the Go packages to compile.
	//
	// Only an explicit list of Go import paths is accepted.
	//
	// E.g. cmd/go or github.com/u-root/u-root/cmds/ls.
	Packages []string

	// TempDir is a temporary directory where the compilation mode compiled
	// binaries can be placed.
	//
	// TempDir should contain no files.
	TempDir string

	// BinaryDir is the initramfs directory for built binaries.
	//
	// BinaryDir must be specified.
	BinaryDir string
}

Opts are arguments to the Builder.Build function.

type Package

type Package struct {
	// contains filtered or unexported fields
}

Package is a Go package.

It holds AST, type, file, and Go package information about a Go package.

func NewPackage

func NewPackage(name string, p *build.Package, importer types.Importer) (*Package, error)

NewPackage gathers AST, type, and token information about package p, using the given importer to resolve dependencies.

func NewPackageFromEnv

func NewPackageFromEnv(env golang.Environ, importPath string, importer types.Importer) (*Package, error)

NewPackageFromEnv finds the package identified by importPath, and gathers AST, type, and token information.

func (*Package) Rewrite

func (p *Package) Rewrite(destDir, bbImportPath string) error

Rewrite rewrites p into destDir as a bb package using bbImportPath for the bb implementation.

type SourceBuilder

type SourceBuilder struct{}

SourceBuilder

func (SourceBuilder) Build

func (SourceBuilder) Build(af initramfs.Files, opts Opts) error

Build is an implementation of Build that includes opts.Packages' full source in the initramfs.

It then also includes the Go toolchain (go, compile, link, asm) and an init process that can compile other programs in the initramfs.

func (SourceBuilder) DefaultBinaryDir

func (SourceBuilder) DefaultBinaryDir() string

DefaultBinaryDir implements Builder.DefaultBinaryDir.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL