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

     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/internal/quoted"
    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  	raw     string
    26  	present bool
    27  	values  []ppfValue
    28  }
    29  
    30  // A ppfValue is a single <pattern>=<flags> per-package flag value.
    31  type ppfValue struct {
    32  	match func(*Package) bool // compiled pattern
    33  	flags []string
    34  }
    35  
    36  // Set is called each time the flag is encountered on the command line.
    37  func (f *PerPackageFlag) Set(v string) error {
    38  	return f.set(v, base.Cwd())
    39  }
    40  
    41  // set is the implementation of Set, taking a cwd (current working directory) for easier testing.
    42  func (f *PerPackageFlag) set(v, cwd string) error {
    43  	f.raw = v
    44  	f.present = true
    45  	match := func(p *Package) bool { return p.Internal.CmdlinePkg || p.Internal.CmdlineFiles } // default predicate with no pattern
    46  	// For backwards compatibility with earlier flag splitting, ignore spaces around flags.
    47  	v = strings.TrimSpace(v)
    48  	if v == "" {
    49  		// Special case: -gcflags="" means no flags for command-line arguments
    50  		// (overrides previous -gcflags="-whatever").
    51  		f.values = append(f.values, ppfValue{match, []string{}})
    52  		return nil
    53  	}
    54  	if !strings.HasPrefix(v, "-") {
    55  		i := strings.Index(v, "=")
    56  		if i < 0 {
    57  			return fmt.Errorf("missing =<value> in <pattern>=<value>")
    58  		}
    59  		if i == 0 {
    60  			return fmt.Errorf("missing <pattern> in <pattern>=<value>")
    61  		}
    62  		if v[0] == '\'' || v[0] == '"' {
    63  			return fmt.Errorf("parameter may not start with quote character %c", v[0])
    64  		}
    65  		pattern := strings.TrimSpace(v[:i])
    66  		match = MatchPackage(pattern, cwd)
    67  		v = v[i+1:]
    68  	}
    69  	flags, err := quoted.Split(v)
    70  	if err != nil {
    71  		return err
    72  	}
    73  	if flags == nil {
    74  		flags = []string{}
    75  	}
    76  	f.values = append(f.values, ppfValue{match, flags})
    77  	return nil
    78  }
    79  
    80  func (f *PerPackageFlag) String() string { return f.raw }
    81  
    82  // Present reports whether the flag appeared on the command line.
    83  func (f *PerPackageFlag) Present() bool {
    84  	return f.present
    85  }
    86  
    87  // For returns the flags to use for the given package.
    88  func (f *PerPackageFlag) For(p *Package) []string {
    89  	flags := []string{}
    90  	for _, v := range f.values {
    91  		if v.match(p) {
    92  			flags = v.flags
    93  		}
    94  	}
    95  	return flags
    96  }
    97  

View as plain text