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