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