mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
517 lines
16 KiB
Go
517 lines
16 KiB
Go
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||
|
|
// Use of this source code is governed by a BSD-style
|
||
|
|
// license that can be found in the LICENSE file.
|
||
|
|
|
||
|
|
package gc
|
||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/json"
|
||
|
|
"flag"
|
||
|
|
"fmt"
|
||
|
|
"io/ioutil"
|
||
|
|
"log"
|
||
|
|
"os"
|
||
|
|
"runtime"
|
||
|
|
"strconv"
|
||
|
|
"strings"
|
||
|
|
|
||
|
|
"cmd/compile/internal/logopt"
|
||
|
|
"cmd/compile/internal/ssa"
|
||
|
|
"cmd/compile/internal/types"
|
||
|
|
"cmd/internal/dwarf"
|
||
|
|
"cmd/internal/obj"
|
||
|
|
"cmd/internal/objabi"
|
||
|
|
"cmd/internal/sys"
|
||
|
|
)
|
||
|
|
|
||
|
|
func usage() {
|
||
|
|
fmt.Fprintf(os.Stderr, "usage: compile [options] file.go...\n")
|
||
|
|
objabi.Flagprint(os.Stderr)
|
||
|
|
Exit(2)
|
||
|
|
}
|
||
|
|
|
||
|
|
var Flag Flags
|
||
|
|
|
||
|
|
// gc debug flags
|
||
|
|
type Flags struct {
|
||
|
|
Percent, B, C, E,
|
||
|
|
K, L, N, S,
|
||
|
|
W, LowerE, LowerH, LowerJ,
|
||
|
|
LowerL, LowerM, LowerR, LowerW int
|
||
|
|
CompilingRuntime bool
|
||
|
|
Std bool
|
||
|
|
D string
|
||
|
|
AsmHdr string
|
||
|
|
BuildID string
|
||
|
|
LowerC int
|
||
|
|
Complete bool
|
||
|
|
LowerD string
|
||
|
|
Dwarf bool
|
||
|
|
GenDwarfInl int
|
||
|
|
InstallSuffix string
|
||
|
|
Lang string
|
||
|
|
LinkObj string
|
||
|
|
Live int
|
||
|
|
MSan bool
|
||
|
|
NoLocalImports bool
|
||
|
|
LowerO string
|
||
|
|
Pack bool
|
||
|
|
Race bool
|
||
|
|
Spectre string
|
||
|
|
LowerT bool
|
||
|
|
TrimPath string
|
||
|
|
WB bool
|
||
|
|
Shared bool
|
||
|
|
Dynlink bool
|
||
|
|
GoVersion string
|
||
|
|
SymABIs string
|
||
|
|
CPUProfile string
|
||
|
|
MemProfile string
|
||
|
|
TraceProfile string
|
||
|
|
BlockProfile string
|
||
|
|
MutexProfile string
|
||
|
|
Bench string
|
||
|
|
SmallFrames bool
|
||
|
|
JSON string
|
||
|
|
|
||
|
|
Cfg struct {
|
||
|
|
Embed struct {
|
||
|
|
Patterns map[string][]string
|
||
|
|
Files map[string]string
|
||
|
|
}
|
||
|
|
ImportDirs []string
|
||
|
|
ImportMap map[string]string
|
||
|
|
PackageFile map[string]string
|
||
|
|
SpectreIndex bool
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func ParseFlags() {
|
||
|
|
Wasm := objabi.GOARCH == "wasm"
|
||
|
|
|
||
|
|
// Whether the limit for stack-allocated objects is much smaller than normal.
|
||
|
|
// This can be helpful for diagnosing certain causes of GC latency. See #27732.
|
||
|
|
Flag.SmallFrames = false
|
||
|
|
Flag.JSON = ""
|
||
|
|
|
||
|
|
flag.BoolVar(&Flag.CompilingRuntime, "+", false, "compiling runtime")
|
||
|
|
flag.BoolVar(&Flag.Std, "std", false, "compiling standard library")
|
||
|
|
flag.StringVar(&Flag.D, "D", "", "set relative `path` for local imports")
|
||
|
|
|
||
|
|
objabi.Flagcount("%", "debug non-static initializers", &Flag.Percent)
|
||
|
|
objabi.Flagcount("B", "disable bounds checking", &Flag.B)
|
||
|
|
objabi.Flagcount("C", "disable printing of columns in error messages", &Flag.C)
|
||
|
|
objabi.Flagcount("E", "debug symbol export", &Flag.E)
|
||
|
|
objabi.Flagcount("K", "debug missing line numbers", &Flag.K)
|
||
|
|
objabi.Flagcount("L", "show full file names in error messages", &Flag.L)
|
||
|
|
objabi.Flagcount("N", "disable optimizations", &Flag.N)
|
||
|
|
objabi.Flagcount("S", "print assembly listing", &Flag.S)
|
||
|
|
objabi.Flagcount("W", "debug parse tree after type checking", &Flag.W)
|
||
|
|
objabi.Flagcount("e", "no limit on number of errors reported", &Flag.LowerE)
|
||
|
|
objabi.Flagcount("h", "halt on error", &Flag.LowerH)
|
||
|
|
objabi.Flagcount("j", "debug runtime-initialized variables", &Flag.LowerJ)
|
||
|
|
objabi.Flagcount("l", "disable inlining", &Flag.LowerL)
|
||
|
|
objabi.Flagcount("m", "print optimization decisions", &Flag.LowerM)
|
||
|
|
objabi.Flagcount("r", "debug generated wrappers", &Flag.LowerR)
|
||
|
|
objabi.Flagcount("w", "debug type checking", &Flag.LowerW)
|
||
|
|
|
||
|
|
objabi.Flagfn1("I", "add `directory` to import search path", addImportDir)
|
||
|
|
objabi.AddVersionFlag() // -V
|
||
|
|
flag.StringVar(&Flag.AsmHdr, "asmhdr", "", "write assembly header to `file`")
|
||
|
|
flag.StringVar(&Flag.BuildID, "buildid", "", "record `id` as the build id in the export metadata")
|
||
|
|
flag.IntVar(&Flag.LowerC, "c", 1, "concurrency during compilation, 1 means no concurrency")
|
||
|
|
flag.BoolVar(&Flag.Complete, "complete", false, "compiling complete package (no C or assembly)")
|
||
|
|
flag.StringVar(&Flag.LowerD, "d", "", "print debug information about items in `list`; try -d help")
|
||
|
|
flag.BoolVar(&Flag.Dwarf, "dwarf", !Wasm, "generate DWARF symbols")
|
||
|
|
flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", true, "add location lists to DWARF in optimized mode")
|
||
|
|
flag.IntVar(&Flag.GenDwarfInl, "gendwarfinl", 2, "generate DWARF inline info records")
|
||
|
|
objabi.Flagfn1("embedcfg", "read go:embed configuration from `file`", readEmbedCfg)
|
||
|
|
objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
|
||
|
|
objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg)
|
||
|
|
flag.StringVar(&Flag.InstallSuffix, "installsuffix", "", "set pkg directory `suffix`")
|
||
|
|
flag.StringVar(&Flag.Lang, "lang", "", "release to compile for")
|
||
|
|
flag.StringVar(&Flag.LinkObj, "linkobj", "", "write linker-specific object to `file`")
|
||
|
|
objabi.Flagcount("live", "debug liveness analysis", &Flag.Live)
|
||
|
|
if sys.MSanSupported(objabi.GOOS, objabi.GOARCH) {
|
||
|
|
flag.BoolVar(&Flag.MSan, "msan", false, "build code compatible with C/C++ memory sanitizer")
|
||
|
|
}
|
||
|
|
flag.BoolVar(&Flag.NoLocalImports, "nolocalimports", false, "reject local (relative) imports")
|
||
|
|
flag.StringVar(&Flag.LowerO, "o", "", "write output to `file`")
|
||
|
|
flag.StringVar(&Ctxt.Pkgpath, "p", "", "set expected package import `path`")
|
||
|
|
flag.BoolVar(&Flag.Pack, "pack", false, "write to file.a instead of file.o")
|
||
|
|
if sys.RaceDetectorSupported(objabi.GOOS, objabi.GOARCH) {
|
||
|
|
flag.BoolVar(&Flag.Race, "race", false, "enable race detector")
|
||
|
|
}
|
||
|
|
flag.StringVar(&Flag.Spectre, "spectre", Flag.Spectre, "enable spectre mitigations in `list` (all, index, ret)")
|
||
|
|
if enableTrace {
|
||
|
|
flag.BoolVar(&Flag.LowerT, "t", false, "trace type-checking")
|
||
|
|
}
|
||
|
|
flag.StringVar(&Flag.TrimPath, "trimpath", "", "remove `prefix` from recorded source file paths")
|
||
|
|
flag.BoolVar(&Ctxt.Debugvlog, "v", false, "increase debug verbosity")
|
||
|
|
flag.BoolVar(&Flag.WB, "wb", true, "enable write barrier")
|
||
|
|
if supportsDynlink(thearch.LinkArch.Arch) {
|
||
|
|
flag.BoolVar(&Flag.Shared, "shared", false, "generate code that can be linked into a shared library")
|
||
|
|
flag.BoolVar(&Flag.Dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
|
||
|
|
flag.BoolVar(&Ctxt.Flag_linkshared, "linkshared", false, "generate code that will be linked against Go shared libraries")
|
||
|
|
}
|
||
|
|
flag.StringVar(&Flag.CPUProfile, "cpuprofile", "", "write cpu profile to `file`")
|
||
|
|
flag.StringVar(&Flag.MemProfile, "memprofile", "", "write memory profile to `file`")
|
||
|
|
flag.Int64Var(&memprofilerate, "memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
|
||
|
|
flag.StringVar(&Flag.GoVersion, "goversion", "", "required version of the runtime")
|
||
|
|
flag.StringVar(&Flag.SymABIs, "symabis", "", "read symbol ABIs from `file`")
|
||
|
|
flag.StringVar(&Flag.TraceProfile, "traceprofile", "", "write an execution trace to `file`")
|
||
|
|
flag.StringVar(&Flag.BlockProfile, "blockprofile", "", "write block profile to `file`")
|
||
|
|
flag.StringVar(&Flag.MutexProfile, "mutexprofile", "", "write mutex profile to `file`")
|
||
|
|
flag.StringVar(&Flag.Bench, "bench", "", "append benchmark times to `file`")
|
||
|
|
flag.BoolVar(&Flag.SmallFrames, "smallframes", false, "reduce the size limit for stack allocated objects")
|
||
|
|
flag.BoolVar(&Ctxt.UseBASEntries, "dwarfbasentries", Ctxt.UseBASEntries, "use base address selection entries in DWARF")
|
||
|
|
flag.StringVar(&Flag.JSON, "json", "", "version,destination for JSON compiler/optimizer logging")
|
||
|
|
|
||
|
|
objabi.Flagparse(usage)
|
||
|
|
|
||
|
|
for _, f := range strings.Split(Flag.Spectre, ",") {
|
||
|
|
f = strings.TrimSpace(f)
|
||
|
|
switch f {
|
||
|
|
default:
|
||
|
|
log.Fatalf("unknown setting -spectre=%s", f)
|
||
|
|
case "":
|
||
|
|
// nothing
|
||
|
|
case "all":
|
||
|
|
Flag.Cfg.SpectreIndex = true
|
||
|
|
Ctxt.Retpoline = true
|
||
|
|
case "index":
|
||
|
|
Flag.Cfg.SpectreIndex = true
|
||
|
|
case "ret":
|
||
|
|
Ctxt.Retpoline = true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if Flag.Cfg.SpectreIndex {
|
||
|
|
switch objabi.GOARCH {
|
||
|
|
case "amd64":
|
||
|
|
// ok
|
||
|
|
default:
|
||
|
|
log.Fatalf("GOARCH=%s does not support -spectre=index", objabi.GOARCH)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Record flags that affect the build result. (And don't
|
||
|
|
// record flags that don't, since that would cause spurious
|
||
|
|
// changes in the binary.)
|
||
|
|
recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
|
||
|
|
|
||
|
|
if Flag.SmallFrames {
|
||
|
|
maxStackVarSize = 128 * 1024
|
||
|
|
maxImplicitStackVarSize = 16 * 1024
|
||
|
|
}
|
||
|
|
|
||
|
|
Ctxt.Flag_shared = Flag.Dynlink || Flag.Shared
|
||
|
|
Ctxt.Flag_dynlink = Flag.Dynlink
|
||
|
|
Ctxt.Flag_optimize = Flag.N == 0
|
||
|
|
|
||
|
|
Ctxt.Debugasm = Flag.S
|
||
|
|
if Flag.Dwarf {
|
||
|
|
Ctxt.DebugInfo = debuginfo
|
||
|
|
Ctxt.GenAbstractFunc = genAbstractFunc
|
||
|
|
Ctxt.DwFixups = obj.NewDwarfFixupTable(Ctxt)
|
||
|
|
} else {
|
||
|
|
// turn off inline generation if no dwarf at all
|
||
|
|
Flag.GenDwarfInl = 0
|
||
|
|
Ctxt.Flag_locationlists = false
|
||
|
|
}
|
||
|
|
|
||
|
|
if flag.NArg() < 1 && Flag.LowerD != "help" && Flag.LowerD != "ssa/help" {
|
||
|
|
usage()
|
||
|
|
}
|
||
|
|
|
||
|
|
if Flag.GoVersion != "" && Flag.GoVersion != runtime.Version() {
|
||
|
|
fmt.Printf("compile: version %q does not match go tool version %q\n", runtime.Version(), Flag.GoVersion)
|
||
|
|
Exit(2)
|
||
|
|
}
|
||
|
|
|
||
|
|
checkLang()
|
||
|
|
|
||
|
|
if Flag.SymABIs != "" {
|
||
|
|
readSymABIs(Flag.SymABIs, Ctxt.Pkgpath)
|
||
|
|
}
|
||
|
|
|
||
|
|
thearch.LinkArch.Init(Ctxt)
|
||
|
|
|
||
|
|
if Flag.LowerO == "" {
|
||
|
|
p := flag.Arg(0)
|
||
|
|
if i := strings.LastIndex(p, "/"); i >= 0 {
|
||
|
|
p = p[i+1:]
|
||
|
|
}
|
||
|
|
if runtime.GOOS == "windows" {
|
||
|
|
if i := strings.LastIndex(p, `\`); i >= 0 {
|
||
|
|
p = p[i+1:]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if i := strings.LastIndex(p, "."); i >= 0 {
|
||
|
|
p = p[:i]
|
||
|
|
}
|
||
|
|
suffix := ".o"
|
||
|
|
if Flag.Pack {
|
||
|
|
suffix = ".a"
|
||
|
|
}
|
||
|
|
Flag.LowerO = p + suffix
|
||
|
|
}
|
||
|
|
|
||
|
|
startProfile()
|
||
|
|
|
||
|
|
if Flag.Race && Flag.MSan {
|
||
|
|
log.Fatal("cannot use both -race and -msan")
|
||
|
|
}
|
||
|
|
if Flag.Race || Flag.MSan {
|
||
|
|
// -race and -msan imply -d=checkptr for now.
|
||
|
|
Debug_checkptr = 1
|
||
|
|
}
|
||
|
|
if ispkgin(omit_pkgs) {
|
||
|
|
Flag.Race = false
|
||
|
|
Flag.MSan = false
|
||
|
|
}
|
||
|
|
if Flag.Race {
|
||
|
|
racepkg = types.NewPkg("runtime/race", "")
|
||
|
|
}
|
||
|
|
if Flag.MSan {
|
||
|
|
msanpkg = types.NewPkg("runtime/msan", "")
|
||
|
|
}
|
||
|
|
if Flag.Race || Flag.MSan {
|
||
|
|
instrumenting = true
|
||
|
|
}
|
||
|
|
|
||
|
|
if Flag.CompilingRuntime && Flag.N != 0 {
|
||
|
|
log.Fatal("cannot disable optimizations while compiling runtime")
|
||
|
|
}
|
||
|
|
if Flag.LowerC < 1 {
|
||
|
|
log.Fatalf("-c must be at least 1, got %d", Flag.LowerC)
|
||
|
|
}
|
||
|
|
if Flag.LowerC > 1 && !concurrentBackendAllowed() {
|
||
|
|
log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args)
|
||
|
|
}
|
||
|
|
if Ctxt.Flag_locationlists && len(Ctxt.Arch.DWARFRegisters) == 0 {
|
||
|
|
log.Fatalf("location lists requested but register mapping not available on %v", Ctxt.Arch.Name)
|
||
|
|
}
|
||
|
|
|
||
|
|
// parse -d argument
|
||
|
|
if Flag.LowerD != "" {
|
||
|
|
Split:
|
||
|
|
for _, name := range strings.Split(Flag.LowerD, ",") {
|
||
|
|
if name == "" {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
// display help about the -d option itself and quit
|
||
|
|
if name == "help" {
|
||
|
|
fmt.Print(debugHelpHeader)
|
||
|
|
maxLen := len("ssa/help")
|
||
|
|
for _, t := range debugtab {
|
||
|
|
if len(t.name) > maxLen {
|
||
|
|
maxLen = len(t.name)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for _, t := range debugtab {
|
||
|
|
fmt.Printf("\t%-*s\t%s\n", maxLen, t.name, t.help)
|
||
|
|
}
|
||
|
|
// ssa options have their own help
|
||
|
|
fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging")
|
||
|
|
fmt.Print(debugHelpFooter)
|
||
|
|
os.Exit(0)
|
||
|
|
}
|
||
|
|
val, valstring, haveInt := 1, "", true
|
||
|
|
if i := strings.IndexAny(name, "=:"); i >= 0 {
|
||
|
|
var err error
|
||
|
|
name, valstring = name[:i], name[i+1:]
|
||
|
|
val, err = strconv.Atoi(valstring)
|
||
|
|
if err != nil {
|
||
|
|
val, haveInt = 1, false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for _, t := range debugtab {
|
||
|
|
if t.name != name {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
switch vp := t.val.(type) {
|
||
|
|
case nil:
|
||
|
|
// Ignore
|
||
|
|
case *string:
|
||
|
|
*vp = valstring
|
||
|
|
case *int:
|
||
|
|
if !haveInt {
|
||
|
|
log.Fatalf("invalid debug value %v", name)
|
||
|
|
}
|
||
|
|
*vp = val
|
||
|
|
default:
|
||
|
|
panic("bad debugtab type")
|
||
|
|
}
|
||
|
|
continue Split
|
||
|
|
}
|
||
|
|
// special case for ssa for now
|
||
|
|
if strings.HasPrefix(name, "ssa/") {
|
||
|
|
// expect form ssa/phase/flag
|
||
|
|
// e.g. -d=ssa/generic_cse/time
|
||
|
|
// _ in phase name also matches space
|
||
|
|
phase := name[4:]
|
||
|
|
flag := "debug" // default flag is debug
|
||
|
|
if i := strings.Index(phase, "/"); i >= 0 {
|
||
|
|
flag = phase[i+1:]
|
||
|
|
phase = phase[:i]
|
||
|
|
}
|
||
|
|
err := ssa.PhaseOption(phase, flag, val, valstring)
|
||
|
|
if err != "" {
|
||
|
|
log.Fatalf(err)
|
||
|
|
}
|
||
|
|
continue Split
|
||
|
|
}
|
||
|
|
log.Fatalf("unknown debug key -d %s\n", name)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if Flag.CompilingRuntime {
|
||
|
|
// Runtime can't use -d=checkptr, at least not yet.
|
||
|
|
Debug_checkptr = 0
|
||
|
|
|
||
|
|
// Fuzzing the runtime isn't interesting either.
|
||
|
|
Debug_libfuzzer = 0
|
||
|
|
}
|
||
|
|
|
||
|
|
// set via a -d flag
|
||
|
|
Ctxt.Debugpcln = Debug_pctab
|
||
|
|
if Flag.Dwarf {
|
||
|
|
dwarf.EnableLogging(Debug_gendwarfinl != 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
if Debug_softfloat != 0 {
|
||
|
|
thearch.SoftFloat = true
|
||
|
|
}
|
||
|
|
|
||
|
|
// enable inlining. for now:
|
||
|
|
// default: inlining on. (Debug.l == 1)
|
||
|
|
// -l: inlining off (Debug.l == 0)
|
||
|
|
// -l=2, -l=3: inlining on again, with extra debugging (Debug.l > 1)
|
||
|
|
if Flag.LowerL <= 1 {
|
||
|
|
Flag.LowerL = 1 - Flag.LowerL
|
||
|
|
}
|
||
|
|
|
||
|
|
if Flag.JSON != "" { // parse version,destination from json logging optimization.
|
||
|
|
logopt.LogJsonOption(Flag.JSON)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// concurrentFlagOk reports whether the current compiler flags
|
||
|
|
// are compatible with concurrent compilation.
|
||
|
|
func concurrentFlagOk() bool {
|
||
|
|
// TODO(rsc): Many of these are fine. Remove them.
|
||
|
|
return Flag.Percent == 0 &&
|
||
|
|
Flag.E == 0 &&
|
||
|
|
Flag.K == 0 &&
|
||
|
|
Flag.L == 0 &&
|
||
|
|
Flag.LowerH == 0 &&
|
||
|
|
Flag.LowerJ == 0 &&
|
||
|
|
Flag.LowerM == 0 &&
|
||
|
|
Flag.LowerR == 0
|
||
|
|
}
|
||
|
|
|
||
|
|
func concurrentBackendAllowed() bool {
|
||
|
|
if !concurrentFlagOk() {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
// Debug.S by itself is ok, because all printing occurs
|
||
|
|
// while writing the object file, and that is non-concurrent.
|
||
|
|
// Adding Debug_vlog, however, causes Debug.S to also print
|
||
|
|
// while flushing the plist, which happens concurrently.
|
||
|
|
if Ctxt.Debugvlog || Flag.LowerD != "" || Flag.Live > 0 {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
// TODO: Test and delete this condition.
|
||
|
|
if objabi.Fieldtrack_enabled != 0 {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
// TODO: fix races and enable the following flags
|
||
|
|
if Ctxt.Flag_shared || Ctxt.Flag_dynlink || Flag.Race {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
|
||
|
|
func addImportDir(dir string) {
|
||
|
|
if dir != "" {
|
||
|
|
Flag.Cfg.ImportDirs = append(Flag.Cfg.ImportDirs, dir)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func addImportMap(s string) {
|
||
|
|
if Flag.Cfg.ImportMap == nil {
|
||
|
|
Flag.Cfg.ImportMap = make(map[string]string)
|
||
|
|
}
|
||
|
|
if strings.Count(s, "=") != 1 {
|
||
|
|
log.Fatal("-importmap argument must be of the form source=actual")
|
||
|
|
}
|
||
|
|
i := strings.Index(s, "=")
|
||
|
|
source, actual := s[:i], s[i+1:]
|
||
|
|
if source == "" || actual == "" {
|
||
|
|
log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty")
|
||
|
|
}
|
||
|
|
Flag.Cfg.ImportMap[source] = actual
|
||
|
|
}
|
||
|
|
|
||
|
|
func readImportCfg(file string) {
|
||
|
|
if Flag.Cfg.ImportMap == nil {
|
||
|
|
Flag.Cfg.ImportMap = make(map[string]string)
|
||
|
|
}
|
||
|
|
Flag.Cfg.PackageFile = map[string]string{}
|
||
|
|
data, err := ioutil.ReadFile(file)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatalf("-importcfg: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
for lineNum, line := range strings.Split(string(data), "\n") {
|
||
|
|
lineNum++ // 1-based
|
||
|
|
line = strings.TrimSpace(line)
|
||
|
|
if line == "" || strings.HasPrefix(line, "#") {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
var verb, args string
|
||
|
|
if i := strings.Index(line, " "); i < 0 {
|
||
|
|
verb = line
|
||
|
|
} else {
|
||
|
|
verb, args = line[:i], strings.TrimSpace(line[i+1:])
|
||
|
|
}
|
||
|
|
var before, after string
|
||
|
|
if i := strings.Index(args, "="); i >= 0 {
|
||
|
|
before, after = args[:i], args[i+1:]
|
||
|
|
}
|
||
|
|
switch verb {
|
||
|
|
default:
|
||
|
|
log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb)
|
||
|
|
case "importmap":
|
||
|
|
if before == "" || after == "" {
|
||
|
|
log.Fatalf(`%s:%d: invalid importmap: syntax is "importmap old=new"`, file, lineNum)
|
||
|
|
}
|
||
|
|
Flag.Cfg.ImportMap[before] = after
|
||
|
|
case "packagefile":
|
||
|
|
if before == "" || after == "" {
|
||
|
|
log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum)
|
||
|
|
}
|
||
|
|
Flag.Cfg.PackageFile[before] = after
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func readEmbedCfg(file string) {
|
||
|
|
data, err := ioutil.ReadFile(file)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatalf("-embedcfg: %v", err)
|
||
|
|
}
|
||
|
|
if err := json.Unmarshal(data, &Flag.Cfg.Embed); err != nil {
|
||
|
|
log.Fatalf("%s: %v", file, err)
|
||
|
|
}
|
||
|
|
if Flag.Cfg.Embed.Patterns == nil {
|
||
|
|
log.Fatalf("%s: invalid embedcfg: missing Patterns", file)
|
||
|
|
}
|
||
|
|
if Flag.Cfg.Embed.Files == nil {
|
||
|
|
log.Fatalf("%s: invalid embedcfg: missing Files", file)
|
||
|
|
}
|
||
|
|
}
|