xref: /aosp_15_r20/external/toolchain-utils/compiler_wrapper/remote_build_flags.go (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
1*760c253cSXin Li// Copyright 2019 The ChromiumOS Authors
2*760c253cSXin Li// Use of this source code is governed by a BSD-style license that can be
3*760c253cSXin Li// found in the LICENSE file.
4*760c253cSXin Li
5*760c253cSXin Lipackage main
6*760c253cSXin Li
7*760c253cSXin Liimport (
8*760c253cSXin Li	"errors"
9*760c253cSXin Li	"fmt"
10*760c253cSXin Li	"os"
11*760c253cSXin Li	"strings"
12*760c253cSXin Li)
13*760c253cSXin Li
14*760c253cSXin Livar errNoSuchCmdlineArg = errors.New("no such commandline argument")
15*760c253cSXin Li
16*760c253cSXin Li// Removes one flag from `builder`, assuming that a value follows the flag. Two formats are
17*760c253cSXin Li// supported for this: `--foo=bar` and `--foo bar`. In either case, "bar" will be returned as the
18*760c253cSXin Li// `value`.
19*760c253cSXin Li//
20*760c253cSXin Li// If no flag is found on the commandline, this returns the `errNoSuchCmdlineArg` error. `builder`
21*760c253cSXin Li// is unmodified if this error is returned, but its contents are unspecified if any other error is
22*760c253cSXin Li// returned.
23*760c253cSXin Li//
24*760c253cSXin Li// In the case of multiple such flags, only the first encountered will be removed.
25*760c253cSXin Lifunc removeOneUserCmdlineFlagWithValue(builder *commandBuilder, flagName string) (flagValue string, err error) {
26*760c253cSXin Li	const (
27*760c253cSXin Li		searchingForFlag uint8 = iota
28*760c253cSXin Li		searchingForValue
29*760c253cSXin Li		searchComplete
30*760c253cSXin Li	)
31*760c253cSXin Li
32*760c253cSXin Li	flagRequiresAValue := func() error { return newUserErrorf("flag %q requires a value", flagName) }
33*760c253cSXin Li	searchState := searchingForFlag
34*760c253cSXin Li	builder.transformArgs(func(arg builderArg) string {
35*760c253cSXin Li		if err != nil {
36*760c253cSXin Li			return arg.value
37*760c253cSXin Li		}
38*760c253cSXin Li
39*760c253cSXin Li		switch searchState {
40*760c253cSXin Li		case searchingForFlag:
41*760c253cSXin Li			if !arg.fromUser {
42*760c253cSXin Li				return arg.value
43*760c253cSXin Li			}
44*760c253cSXin Li
45*760c253cSXin Li			if arg.value == flagName {
46*760c253cSXin Li				searchState = searchingForValue
47*760c253cSXin Li				return ""
48*760c253cSXin Li			}
49*760c253cSXin Li
50*760c253cSXin Li			isArgEq := strings.HasPrefix(arg.value, flagName) && arg.value[len(flagName)] == '='
51*760c253cSXin Li			if !isArgEq {
52*760c253cSXin Li				return arg.value
53*760c253cSXin Li			}
54*760c253cSXin Li
55*760c253cSXin Li			flagValue = arg.value[len(flagName)+1:]
56*760c253cSXin Li			searchState = searchComplete
57*760c253cSXin Li			return ""
58*760c253cSXin Li
59*760c253cSXin Li		case searchingForValue:
60*760c253cSXin Li			if !arg.fromUser {
61*760c253cSXin Li				err = flagRequiresAValue()
62*760c253cSXin Li				return arg.value
63*760c253cSXin Li			}
64*760c253cSXin Li
65*760c253cSXin Li			flagValue = arg.value
66*760c253cSXin Li			searchState = searchComplete
67*760c253cSXin Li			return ""
68*760c253cSXin Li
69*760c253cSXin Li		case searchComplete:
70*760c253cSXin Li			return arg.value
71*760c253cSXin Li
72*760c253cSXin Li		default:
73*760c253cSXin Li			panic(fmt.Sprintf("unknown search state: %v", searchState))
74*760c253cSXin Li		}
75*760c253cSXin Li	})
76*760c253cSXin Li
77*760c253cSXin Li	if err != nil {
78*760c253cSXin Li		return "", err
79*760c253cSXin Li	}
80*760c253cSXin Li
81*760c253cSXin Li	switch searchState {
82*760c253cSXin Li	case searchingForFlag:
83*760c253cSXin Li		return "", errNoSuchCmdlineArg
84*760c253cSXin Li
85*760c253cSXin Li	case searchingForValue:
86*760c253cSXin Li		return "", flagRequiresAValue()
87*760c253cSXin Li
88*760c253cSXin Li	case searchComplete:
89*760c253cSXin Li		return flagValue, nil
90*760c253cSXin Li
91*760c253cSXin Li	default:
92*760c253cSXin Li		panic(fmt.Sprintf("unknown search state: %v", searchState))
93*760c253cSXin Li	}
94*760c253cSXin Li}
95*760c253cSXin Li
96*760c253cSXin Lifunc processGomaCccFlags(builder *commandBuilder, inheritFromEnv bool) (gomaUsed bool, err error) {
97*760c253cSXin Li	gomaPath, err := removeOneUserCmdlineFlagWithValue(builder, "--gomacc-path")
98*760c253cSXin Li	if err != nil && err != errNoSuchCmdlineArg {
99*760c253cSXin Li		return false, err
100*760c253cSXin Li	}
101*760c253cSXin Li
102*760c253cSXin Li	if inheritFromEnv && (err == errNoSuchCmdlineArg || gomaPath == "") {
103*760c253cSXin Li		gomaPath, _ = builder.env.getenv("GOMACC_PATH")
104*760c253cSXin Li	}
105*760c253cSXin Li
106*760c253cSXin Li	if gomaPath != "" {
107*760c253cSXin Li		if _, err := os.Lstat(gomaPath); err == nil {
108*760c253cSXin Li			builder.wrapPath(gomaPath)
109*760c253cSXin Li			return true, nil
110*760c253cSXin Li		}
111*760c253cSXin Li	}
112*760c253cSXin Li	return false, nil
113*760c253cSXin Li}
114*760c253cSXin Li
115*760c253cSXin Lifunc processRewrapperCcFlags(builder *commandBuilder) (rewrapperUsed bool, err error) {
116*760c253cSXin Li	rewrapperPath, pathErr := removeOneUserCmdlineFlagWithValue(builder, "--rewrapper-path")
117*760c253cSXin Li	if pathErr != nil && pathErr != errNoSuchCmdlineArg {
118*760c253cSXin Li		return false, err
119*760c253cSXin Li	}
120*760c253cSXin Li
121*760c253cSXin Li	rewrapperCfg, cfgErr := removeOneUserCmdlineFlagWithValue(builder, "--rewrapper-cfg")
122*760c253cSXin Li	if cfgErr != nil && cfgErr != errNoSuchCmdlineArg {
123*760c253cSXin Li		return false, err
124*760c253cSXin Li	}
125*760c253cSXin Li
126*760c253cSXin Li	if pathErr == errNoSuchCmdlineArg {
127*760c253cSXin Li		if cfgErr != errNoSuchCmdlineArg {
128*760c253cSXin Li			return false, newUserErrorf("--rewrapper-path must be specified if --rewrapper-cfg is")
129*760c253cSXin Li		}
130*760c253cSXin Li		return false, nil
131*760c253cSXin Li	}
132*760c253cSXin Li
133*760c253cSXin Li	if cfgErr == errNoSuchCmdlineArg {
134*760c253cSXin Li		return false, newUserErrorf("--rewrapper-cfg must be specified if --rewrapper-path is")
135*760c253cSXin Li	}
136*760c253cSXin Li
137*760c253cSXin Li	// It's unclear that we should have a similar fallback to gomacc if --rewrapper-path doesn't
138*760c253cSXin Li	// exist, so don't until it's obviously necessary.
139*760c253cSXin Li	builder.wrapPath(rewrapperPath, "-cfg", rewrapperCfg)
140*760c253cSXin Li	return true, nil
141*760c253cSXin Li}
142*760c253cSXin Li
143*760c253cSXin Lifunc processRemoteBuildFlags(builder *commandBuilder) (remoteBuildUsed bool, err error) {
144*760c253cSXin Li	rewrapperUsed, err := processRewrapperCcFlags(builder)
145*760c253cSXin Li	if err != nil {
146*760c253cSXin Li		return rewrapperUsed, err
147*760c253cSXin Li	}
148*760c253cSXin Li
149*760c253cSXin Li	inheritGomaFromEnv := !rewrapperUsed
150*760c253cSXin Li	gomaUsed, err := processGomaCccFlags(builder, inheritGomaFromEnv)
151*760c253cSXin Li	remoteBuildUsed = gomaUsed || rewrapperUsed
152*760c253cSXin Li	if err != nil {
153*760c253cSXin Li		return remoteBuildUsed, err
154*760c253cSXin Li	}
155*760c253cSXin Li
156*760c253cSXin Li	if gomaUsed && rewrapperUsed {
157*760c253cSXin Li		return true, newUserErrorf("rewrapper and gomacc are mutually exclusive")
158*760c253cSXin Li	}
159*760c253cSXin Li	return remoteBuildUsed, nil
160*760c253cSXin Li}
161