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