Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/go/internal/load/flag.go

Documentation: cmd/go/internal/load

     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  	// For backwards compatibility with earlier flag splitting, ignore spaces around flags.
    45  	v = strings.TrimSpace(v)
    46  	if v == "" {
    47  		// Special case: -gcflags="" means no flags for command-line arguments
    48  		// (overrides previous -gcflags="-whatever").
    49  		f.values = append(f.values, ppfValue{match, []string{}})
    50  		return nil
    51  	}
    52  	if !strings.HasPrefix(v, "-") {
    53  		i := strings.Index(v, "=")
    54  		if i < 0 {
    55  			return fmt.Errorf("missing =<value> in <pattern>=<value>")
    56  		}
    57  		if i == 0 {
    58  			return fmt.Errorf("missing <pattern> in <pattern>=<value>")
    59  		}
    60  		pattern := strings.TrimSpace(v[:i])
    61  		match = MatchPackage(pattern, cwd)
    62  		v = v[i+1:]
    63  	}
    64  	flags, err := str.SplitQuotedFields(v)
    65  	if err != nil {
    66  		return err
    67  	}
    68  	if flags == nil {
    69  		flags = []string{}
    70  	}
    71  	f.values = append(f.values, ppfValue{match, flags})
    72  	return nil
    73  }
    74  
    75  // String is required to implement flag.Value.
    76  // It is not used, because cmd/go never calls flag.PrintDefaults.
    77  func (f *PerPackageFlag) String() string { return "<PerPackageFlag>" }
    78  
    79  // Present reports whether the flag appeared on the command line.
    80  func (f *PerPackageFlag) Present() bool {
    81  	return f.present
    82  }
    83  
    84  // For returns the flags to use for the given package.
    85  func (f *PerPackageFlag) For(p *Package) []string {
    86  	flags := []string{}
    87  	for _, v := range f.values {
    88  		if v.match(p) {
    89  			flags = v.flags
    90  		}
    91  	}
    92  	return flags
    93  }
    94  

View as plain text