github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/cmd/go/internal/load/flag.go (about) 1 // Copyright 2017 The Go 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 load 6 7 import ( 8 "cmd/go/internal/base" 9 "cmd/go/internal/str" 10 "fmt" 11 "strings" 12 ) 13 14 var ( 15 BuildAsmflags PerPackageFlag // -asmflags 16 BuildGcflags PerPackageFlag // -gcflags 17 BuildLdflags PerPackageFlag // -ldflags 18 BuildGccgoflags PerPackageFlag // -gccgoflags 19 ) 20 21 // A PerPackageFlag is a command-line flag implementation (a flag.Value) 22 // that allows specifying different effective flags for different packages. 23 // See 'go help build' for more details about per-package flags. 24 type PerPackageFlag struct { 25 present bool 26 values []ppfValue 27 } 28 29 // A ppfValue is a single <pattern>=<flags> per-package flag value. 30 type ppfValue struct { 31 match func(*Package) bool // compiled pattern 32 flags []string 33 } 34 35 // Set is called each time the flag is encountered on the command line. 36 func (f *PerPackageFlag) Set(v string) error { 37 return f.set(v, base.Cwd) 38 } 39 40 // set is the implementation of Set, taking a cwd (current working directory) for easier testing. 41 func (f *PerPackageFlag) set(v, cwd string) error { 42 f.present = true 43 match := func(p *Package) bool { return p.Internal.CmdlinePkg || p.Internal.CmdlineFiles } // default predicate with no pattern 44 if v == "" { 45 // Special case: -gcflags="" means no flags for command-line arguments 46 // (overrides previous -gcflags="-whatever"). 47 f.values = append(f.values, ppfValue{match, []string{}}) 48 return nil 49 } 50 if !strings.HasPrefix(v, "-") { 51 i := strings.Index(v, "=") 52 if i < 0 { 53 return fmt.Errorf("missing =<value> in <pattern>=<value>") 54 } 55 if i == 0 { 56 return fmt.Errorf("missing <pattern> in <pattern>=<value>") 57 } 58 pattern := v[:i] 59 match = MatchPackage(pattern, cwd) 60 v = v[i+1:] 61 } 62 flags, err := str.SplitQuotedFields(v) 63 if err != nil { 64 return err 65 } 66 if flags == nil { 67 flags = []string{} 68 } 69 f.values = append(f.values, ppfValue{match, flags}) 70 return nil 71 } 72 73 // String is required to implement flag.Value. 74 // It is not used, because cmd/go never calls flag.PrintDefaults. 75 func (f *PerPackageFlag) String() string { return "<PerPackageFlag>" } 76 77 // Present reports whether the flag appeared on the command line. 78 func (f *PerPackageFlag) Present() bool { 79 return f.present 80 } 81 82 // For returns the flags to use for the given package. 83 func (f *PerPackageFlag) For(p *Package) []string { 84 flags := []string{} 85 for _, v := range f.values { 86 if v.match(p) { 87 flags = v.flags 88 } 89 } 90 return flags 91 } 92 93 var cmdlineMatchers []func(*Package) bool 94 95 // SetCmdlinePatterns records the set of patterns given on the command line, 96 // for use by the PerPackageFlags. 97 func SetCmdlinePatterns(args []string) { 98 setCmdlinePatterns(args, base.Cwd) 99 } 100 101 func setCmdlinePatterns(args []string, cwd string) { 102 if len(args) == 0 { 103 args = []string{"."} 104 } 105 cmdlineMatchers = nil // allow reset for testing 106 for _, arg := range args { 107 cmdlineMatchers = append(cmdlineMatchers, MatchPackage(arg, cwd)) 108 } 109 } 110 111 // isCmdlinePkg reports whether p is a package listed on the command line. 112 func isCmdlinePkg(p *Package) bool { 113 for _, m := range cmdlineMatchers { 114 if m(p) { 115 return true 116 } 117 } 118 return false 119 }