github.com/aca02djr/gb@v0.4.1/cmd/gb/build.go (about)

     1  package main
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"runtime"
     9  
    10  	"github.com/constabulary/gb"
    11  	"github.com/constabulary/gb/cmd"
    12  )
    13  
    14  func init() {
    15  	registerCommand(BuildCmd)
    16  }
    17  
    18  var (
    19  	// build flags
    20  
    21  	// should we build all packages in this project.
    22  	// defaults to true when build is invoked from the project root.
    23  	A bool
    24  
    25  	// should we perform a release build +release tag ?
    26  	// defaults to false, +debug.
    27  	R bool
    28  
    29  	// force rebuild of packages
    30  	F bool
    31  
    32  	// skip caching of packages
    33  	FF bool
    34  
    35  	// enable race runtime
    36  	race bool
    37  
    38  	ldflags, gcflags []string
    39  
    40  	P int // number of executors to run in parallel
    41  
    42  	dotfile string // path to dot output file
    43  
    44  	buildtags []string
    45  )
    46  
    47  func addBuildFlags(fs *flag.FlagSet) {
    48  	// TODO(dfc) this should accept a *gb.Context
    49  	fs.BoolVar(&A, "a", false, "build all packages in this project")
    50  	fs.BoolVar(&R, "r", false, "perform a release build")
    51  	fs.BoolVar(&F, "f", false, "rebuild up-to-date packages")
    52  	fs.BoolVar(&FF, "F", false, "do not cache built packages")
    53  	fs.BoolVar(&race, "race", false, "enable race detector")
    54  	fs.IntVar(&P, "P", runtime.NumCPU(), "number of parallel jobs")
    55  	fs.Var((*stringsFlag)(&ldflags), "ldflags", "flags passed to the linker")
    56  	fs.Var((*stringsFlag)(&gcflags), "gcflags", "flags passed to the compiler")
    57  	fs.StringVar(&dotfile, "dotfile", "", "path to dot output file")
    58  	fs.Var((*stringsFlag)(&buildtags), "tags", "")
    59  }
    60  
    61  var BuildCmd = &cmd.Command{
    62  	Name:      "build",
    63  	Short:     "build a package",
    64  	UsageLine: "build [build flags] [packages]",
    65  	Long: `
    66  Build compiles the packages named by the import paths, along with their
    67  dependencies.
    68  
    69  Flags:
    70  
    71  	-f
    72  		ignore cached packages if present, new packages built will overwrite
    73  		any cached packages. This effectively disables incremental
    74  		compilation.
    75  	-F
    76  		do not cache packages, cached packages will still be used for
    77  		incremental compilation. -f -F is advised to disable the package
    78  		caching system.
    79  	-q
    80  		decreases verbosity, effectively raising the output level to ERROR.
    81  		In a successful build, no output will be displayed.
    82  	-P
    83  		The number of build jobs to run in parallel, including test execution.
    84  		By default this is the number of CPUs visible to gb.
    85  	-R
    86  		sets the base of the project root search path from the current working
    87  		directory to the value supplied. Effectively gb changes working
    88  		directory to this path before searching for the project root.
    89  	-dotfile
    90  		if provided, gb will output a dot formatted file of the build steps to
    91  		be performed.
    92  	-ldflags 'flag list'
    93  		arguments to pass on each linker invocation.
    94  	-gcflags 'arg list'
    95  		arguments to pass on each compile invocation.
    96          -race
    97                  enable data race detection.
    98                  Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
    99  	-tags 'tag list'
   100  		additional build tags.
   101  
   102  The list flags accept a space-separated list of strings. To embed spaces in an
   103  element in the list, surround it with either single or double quotes.
   104  
   105  For more about where packages and binaries are installed, run 'gb help project'.
   106  `,
   107  	Run: func(ctx *gb.Context, args []string) error {
   108  		// TODO(dfc) run should take a *gb.Context not a *gb.Project
   109  		ctx.Force = F
   110  		ctx.Install = !FF
   111  
   112  		pkgs, err := resolveRootPackages(ctx, args...)
   113  		if err != nil {
   114  			return err
   115  		}
   116  
   117  		build, err := gb.BuildPackages(pkgs...)
   118  		if err != nil {
   119  			return err
   120  		}
   121  
   122  		if dotfile != "" {
   123  			f, err := os.Create(dotfile)
   124  			if err != nil {
   125  				return err
   126  			}
   127  			defer f.Close()
   128  			printActions(f, build)
   129  		}
   130  
   131  		startSigHandlers()
   132  		return gb.ExecuteConcurrent(build, P, interrupted)
   133  	},
   134  	AddFlags: addBuildFlags,
   135  }
   136  
   137  // Resolver resolves packages.
   138  type Resolver interface {
   139  	Projectdir() string
   140  	// ResolvePackage resolves the import path to a *Package
   141  	ResolvePackage(path string) (*gb.Package, error)
   142  }
   143  
   144  // resolveRootPackages resolves import paths into packages.
   145  // Only packages which exist inside $PROJECT/src are elegable to be
   146  // roots to build or test. Other import paths are discarded.
   147  func resolveRootPackages(r Resolver, paths ...string) ([]*gb.Package, error) {
   148  	var pkgs []*gb.Package
   149  	for _, path := range paths {
   150  		pkg, err := r.ResolvePackage(path)
   151  		if err != nil {
   152  			return pkgs, fmt.Errorf("failed to resolve import path %q: %v", path, err)
   153  		}
   154  		if pkg.SrcRoot == filepath.Join(runtime.GOROOT(), "src") {
   155  			// skip package roots that are not part of this project.
   156  			// TODO(dfc) should gb return an error here?
   157  			continue
   158  		}
   159  		pkgs = append(pkgs, pkg)
   160  	}
   161  	return pkgs, nil
   162  }