1 // Copyright 2009 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.
23 fmt.Fprintf(os.Stderr, "usage: compile [options] file.go...\n")
24 objabi.Flagprint(os.Stderr)
28 // Flag holds the parsed command-line flags.
29 // See ParseFlag for non-zero defaults.
32 // A CountFlag is a counting integer flag.
33 // It accepts -name=value to set the value directly,
34 // but it also accepts -name with no =value to increment the count.
37 // CmdFlags defines the command-line flags (see var Flag).
38 // Each struct field is a different flag, by default named for the lower-case of the field name.
39 // If the flag name is a single letter, the default flag name is left upper-case.
40 // If the flag name is "Lower" followed by a single letter, the default flag name is the lower-case of the last letter.
42 // If this default flag name can't be made right, the `flag` struct tag can be used to replace it,
43 // but this should be done only in exceptional circumstances: it helps everyone if the flag name
44 // is obvious from the field name when the flag is used elsewhere in the compiler sources.
45 // The `flag:"-"` struct tag makes a field invisible to the flag logic and should also be used sparingly.
47 // Each field must have a `help` struct tag giving the flag help message.
49 // The allowed field types are bool, int, string, pointers to those (for values stored elsewhere),
50 // CountFlag (for a counting flag), and func(string) (for a flag that uses special code for parsing).
51 type CmdFlags struct {
53 B CountFlag "help:\"disable bounds checking\""
54 C CountFlag "help:\"disable printing of columns in error messages\""
55 D string "help:\"set relative `path` for local imports\""
56 E CountFlag "help:\"debug symbol export\""
57 G CountFlag "help:\"accept generic code\""
58 I func(string) "help:\"add `directory` to import search path\""
59 K CountFlag "help:\"debug missing line numbers\""
60 L CountFlag "help:\"show full file names in error messages\""
61 N CountFlag "help:\"disable optimizations\""
62 S CountFlag "help:\"print assembly listing\""
63 // V is added by objabi.AddVersionFlag
64 W CountFlag "help:\"debug parse tree after type checking\""
66 LowerC int "help:\"concurrency during compilation (1 means no concurrency)\""
67 LowerD func(string) "help:\"enable debugging settings; try -d help\""
68 LowerE CountFlag "help:\"no limit on number of errors reported\""
69 LowerH CountFlag "help:\"halt on error\""
70 LowerJ CountFlag "help:\"debug runtime-initialized variables\""
71 LowerL CountFlag "help:\"disable inlining\""
72 LowerM CountFlag "help:\"print optimization decisions\""
73 LowerO string "help:\"write output to `file`\""
74 LowerP *string "help:\"set expected package import `path`\"" // &Ctxt.Pkgpath, set below
75 LowerR CountFlag "help:\"debug generated wrappers\""
76 LowerT bool "help:\"enable tracing for debugging the compiler\""
77 LowerW CountFlag "help:\"debug type checking\""
78 LowerV *bool "help:\"increase debug verbosity\""
81 Percent int "flag:\"%\" help:\"debug non-static initializers\""
82 CompilingRuntime bool "flag:\"+\" help:\"compiling runtime\""
85 AsmHdr string "help:\"write assembly header to `file`\""
86 Bench string "help:\"append benchmark times to `file`\""
87 BlockProfile string "help:\"write block profile to `file`\""
88 BuildID string "help:\"record `id` as the build id in the export metadata\""
89 CPUProfile string "help:\"write cpu profile to `file`\""
90 Complete bool "help:\"compiling complete package (no C or assembly)\""
91 ClobberDead bool "help:\"clobber dead stack slots (for debugging)\""
92 ClobberDeadReg bool "help:\"clobber dead registers (for debugging)\""
93 Dwarf bool "help:\"generate DWARF symbols\""
94 DwarfBASEntries *bool "help:\"use base address selection entries in DWARF\"" // &Ctxt.UseBASEntries, set below
95 DwarfLocationLists *bool "help:\"add location lists to DWARF in optimized mode\"" // &Ctxt.Flag_locationlists, set below
96 Dynlink *bool "help:\"support references to Go symbols defined in other shared libraries\"" // &Ctxt.Flag_dynlink, set below
97 EmbedCfg func(string) "help:\"read go:embed configuration from `file`\""
98 GenDwarfInl int "help:\"generate DWARF inline info records\"" // 0=disabled, 1=funcs, 2=funcs+formals/locals
99 GoVersion string "help:\"required version of the runtime\""
100 ImportCfg func(string) "help:\"read import configuration from `file`\""
101 ImportMap func(string) "help:\"add `definition` of the form source=actual to import map\""
102 InstallSuffix string "help:\"set pkg directory `suffix`\""
103 JSON string "help:\"version,file for JSON compiler/optimizer detail output\""
104 Lang string "help:\"Go language version source code expects\""
105 LinkObj string "help:\"write linker-specific object to `file`\""
106 LinkShared *bool "help:\"generate code that will be linked against Go shared libraries\"" // &Ctxt.Flag_linkshared, set below
107 Live CountFlag "help:\"debug liveness analysis\""
108 MSan bool "help:\"build code compatible with C/C++ memory sanitizer\""
109 MemProfile string "help:\"write memory profile to `file`\""
110 MemProfileRate int64 "help:\"set runtime.MemProfileRate to `rate`\""
111 MutexProfile string "help:\"write mutex profile to `file`\""
112 NoLocalImports bool "help:\"reject local (relative) imports\""
113 Pack bool "help:\"write to file.a instead of file.o\""
114 Race bool "help:\"enable race detector\""
115 Shared *bool "help:\"generate code that can be linked into a shared library\"" // &Ctxt.Flag_shared, set below
116 SmallFrames bool "help:\"reduce the size limit for stack allocated objects\"" // small stacks, to diagnose GC latency; see golang.org/issue/27732
117 Spectre string "help:\"enable spectre mitigations in `list` (all, index, ret)\""
118 Std bool "help:\"compiling standard library\""
119 SymABIs string "help:\"read symbol ABIs from `file`\""
120 TraceProfile string "help:\"write an execution trace to `file`\""
121 TrimPath string "help:\"remove `prefix` from recorded source file paths\""
122 WB bool "help:\"enable write barrier\"" // TODO: remove
124 // Configuration derived from flags; not a flag itself.
126 Embed struct { // set by -embedcfg
127 Patterns map[string][]string
128 Files map[string]string
130 ImportDirs []string // appended to by -I
131 ImportMap map[string]string // set by -importmap OR -importcfg
132 PackageFile map[string]string // set by -importcfg; nil means not in use
133 SpectreIndex bool // set by -spectre=index or -spectre=all
134 // Whether we are adding any sort of code instrumentation, such as
135 // when the race detector is enabled.
140 // ParseFlags parses the command-line flags into Flag.
142 Flag.I = addImportDir
145 Flag.LowerD = parseDebug
146 Flag.LowerP = &Ctxt.Pkgpath
147 Flag.LowerV = &Ctxt.Debugvlog
149 Flag.Dwarf = objabi.GOARCH != "wasm"
150 Flag.DwarfBASEntries = &Ctxt.UseBASEntries
151 Flag.DwarfLocationLists = &Ctxt.Flag_locationlists
152 *Flag.DwarfLocationLists = true
153 Flag.Dynlink = &Ctxt.Flag_dynlink
154 Flag.EmbedCfg = readEmbedCfg
156 Flag.ImportCfg = readImportCfg
157 Flag.ImportMap = addImportMap
158 Flag.LinkShared = &Ctxt.Flag_linkshared
159 Flag.Shared = &Ctxt.Flag_shared
161 Debug.InlFuncsWithClosures = 1
163 Debug.Checkptr = -1 // so we can tell whether it is set explicitly
165 Flag.Cfg.ImportMap = make(map[string]string)
167 objabi.AddVersionFlag() // -V
169 objabi.Flagparse(usage)
171 if Flag.MSan && !sys.MSanSupported(objabi.GOOS, objabi.GOARCH) {
172 log.Fatalf("%s/%s does not support -msan", objabi.GOOS, objabi.GOARCH)
174 if Flag.Race && !sys.RaceDetectorSupported(objabi.GOOS, objabi.GOARCH) {
175 log.Fatalf("%s/%s does not support -race", objabi.GOOS, objabi.GOARCH)
177 if (*Flag.Shared || *Flag.Dynlink || *Flag.LinkShared) && !Ctxt.Arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.RISCV64, sys.S390X) {
178 log.Fatalf("%s/%s does not support -shared", objabi.GOOS, objabi.GOARCH)
180 parseSpectre(Flag.Spectre) // left as string for RecordFlags
182 Ctxt.Flag_shared = Ctxt.Flag_dynlink || Ctxt.Flag_shared
183 Ctxt.Flag_optimize = Flag.N == 0
184 Ctxt.Debugasm = int(Flag.S)
190 if Flag.GoVersion != "" && Flag.GoVersion != runtime.Version() {
191 fmt.Printf("compile: version %q does not match go tool version %q\n", runtime.Version(), Flag.GoVersion)
195 if Flag.LowerO == "" {
197 if i := strings.LastIndex(p, "/"); i >= 0 {
200 if runtime.GOOS == "windows" {
201 if i := strings.LastIndex(p, `\`); i >= 0 {
205 if i := strings.LastIndex(p, "."); i >= 0 {
212 Flag.LowerO = p + suffix
215 if Flag.Race && Flag.MSan {
216 log.Fatal("cannot use both -race and -msan")
218 if Flag.Race || Flag.MSan {
219 // -race and -msan imply -d=checkptr for now.
220 if Debug.Checkptr == -1 { // if not set explicitly
225 if Flag.CompilingRuntime && Flag.N != 0 {
226 log.Fatal("cannot disable optimizations while compiling runtime")
229 log.Fatalf("-c must be at least 1, got %d", Flag.LowerC)
231 if Flag.LowerC > 1 && !concurrentBackendAllowed() {
232 log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args)
235 if Flag.CompilingRuntime {
236 // Runtime can't use -d=checkptr, at least not yet.
239 // Fuzzing the runtime isn't interesting either.
243 if Debug.Checkptr == -1 { // if not set explicitly
248 Ctxt.Debugpcln = Debug.PCTab
251 // registerFlags adds flag registrations for all the fields in Flag.
252 // See the comment on type CmdFlags for the rules.
253 func registerFlags() {
255 boolType = reflect.TypeOf(bool(false))
256 intType = reflect.TypeOf(int(0))
257 stringType = reflect.TypeOf(string(""))
258 ptrBoolType = reflect.TypeOf(new(bool))
259 ptrIntType = reflect.TypeOf(new(int))
260 ptrStringType = reflect.TypeOf(new(string))
261 countType = reflect.TypeOf(CountFlag(0))
262 funcType = reflect.TypeOf((func(string))(nil))
265 v := reflect.ValueOf(&Flag).Elem()
267 for i := 0; i < t.NumField(); i++ {
274 if len(f.Name) == 1 {
276 } else if len(f.Name) == 6 && f.Name[:5] == "Lower" && 'A' <= f.Name[5] && f.Name[5] <= 'Z' {
277 name = string(rune(f.Name[5] + 'a' - 'A'))
279 name = strings.ToLower(f.Name)
281 if tag := f.Tag.Get("flag"); tag != "" {
285 help := f.Tag.Get("help")
287 panic(fmt.Sprintf("base.Flag.%s is missing help text", f.Name))
290 if k := f.Type.Kind(); (k == reflect.Ptr || k == reflect.Func) && v.Field(i).IsNil() {
291 panic(fmt.Sprintf("base.Flag.%s is uninitialized %v", f.Name, f.Type))
296 p := v.Field(i).Addr().Interface().(*bool)
297 flag.BoolVar(p, name, *p, help)
299 p := v.Field(i).Addr().Interface().(*int)
300 flag.IntVar(p, name, *p, help)
302 p := v.Field(i).Addr().Interface().(*string)
303 flag.StringVar(p, name, *p, help)
305 p := v.Field(i).Interface().(*bool)
306 flag.BoolVar(p, name, *p, help)
308 p := v.Field(i).Interface().(*int)
309 flag.IntVar(p, name, *p, help)
311 p := v.Field(i).Interface().(*string)
312 flag.StringVar(p, name, *p, help)
314 p := (*int)(v.Field(i).Addr().Interface().(*CountFlag))
315 objabi.Flagcount(name, help, p)
317 f := v.Field(i).Interface().(func(string))
318 objabi.Flagfn1(name, help, f)
323 // concurrentFlagOk reports whether the current compiler flags
324 // are compatible with concurrent compilation.
325 func concurrentFlagOk() bool {
326 // TODO(rsc): Many of these are fine. Remove them.
327 return Flag.Percent == 0 &&
337 func concurrentBackendAllowed() bool {
338 if !concurrentFlagOk() {
342 // Debug.S by itself is ok, because all printing occurs
343 // while writing the object file, and that is non-concurrent.
344 // Adding Debug_vlog, however, causes Debug.S to also print
345 // while flushing the plist, which happens concurrently.
346 if Ctxt.Debugvlog || Debug.Any() || Flag.Live > 0 {
349 // TODO: Test and delete this condition.
350 if objabi.Experiment.FieldTrack {
353 // TODO: fix races and enable the following flags
354 if Ctxt.Flag_shared || Ctxt.Flag_dynlink || Flag.Race {
360 func addImportDir(dir string) {
362 Flag.Cfg.ImportDirs = append(Flag.Cfg.ImportDirs, dir)
366 func addImportMap(s string) {
367 if Flag.Cfg.ImportMap == nil {
368 Flag.Cfg.ImportMap = make(map[string]string)
370 if strings.Count(s, "=") != 1 {
371 log.Fatal("-importmap argument must be of the form source=actual")
373 i := strings.Index(s, "=")
374 source, actual := s[:i], s[i+1:]
375 if source == "" || actual == "" {
376 log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty")
378 Flag.Cfg.ImportMap[source] = actual
381 func readImportCfg(file string) {
382 if Flag.Cfg.ImportMap == nil {
383 Flag.Cfg.ImportMap = make(map[string]string)
385 Flag.Cfg.PackageFile = map[string]string{}
386 data, err := ioutil.ReadFile(file)
388 log.Fatalf("-importcfg: %v", err)
391 for lineNum, line := range strings.Split(string(data), "\n") {
393 line = strings.TrimSpace(line)
394 if line == "" || strings.HasPrefix(line, "#") {
398 var verb, args string
399 if i := strings.Index(line, " "); i < 0 {
402 verb, args = line[:i], strings.TrimSpace(line[i+1:])
404 var before, after string
405 if i := strings.Index(args, "="); i >= 0 {
406 before, after = args[:i], args[i+1:]
410 log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb)
412 if before == "" || after == "" {
413 log.Fatalf(`%s:%d: invalid importmap: syntax is "importmap old=new"`, file, lineNum)
415 Flag.Cfg.ImportMap[before] = after
417 if before == "" || after == "" {
418 log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum)
420 Flag.Cfg.PackageFile[before] = after
425 func readEmbedCfg(file string) {
426 data, err := ioutil.ReadFile(file)
428 log.Fatalf("-embedcfg: %v", err)
430 if err := json.Unmarshal(data, &Flag.Cfg.Embed); err != nil {
431 log.Fatalf("%s: %v", file, err)
433 if Flag.Cfg.Embed.Patterns == nil {
434 log.Fatalf("%s: invalid embedcfg: missing Patterns", file)
436 if Flag.Cfg.Embed.Files == nil {
437 log.Fatalf("%s: invalid embedcfg: missing Files", file)
441 // parseSpectre parses the spectre configuration from the string s.
442 func parseSpectre(s string) {
443 for _, f := range strings.Split(s, ",") {
444 f = strings.TrimSpace(f)
447 log.Fatalf("unknown setting -spectre=%s", f)
451 Flag.Cfg.SpectreIndex = true
452 Ctxt.Retpoline = true
454 Flag.Cfg.SpectreIndex = true
456 Ctxt.Retpoline = true
460 if Flag.Cfg.SpectreIndex {
461 switch objabi.GOARCH {
465 log.Fatalf("GOARCH=%s does not support -spectre=index", objabi.GOARCH)