cmd/link: deprecate -X name value in favor of -X name=value

People invoking the linker directly already have to change their scripts
to use the new "go tool link", so this is a good time to make the -X flag
behave like all other Go flags and take just a single argument.

The old syntax will continue to be accepted (it is rewritten into the new
syntax before flag parsing). Maybe some day we will be able to retire it.

Even if we never retire the old syntax, having the new syntax at least
makes the rewriting much less of a kludge.

Change-Id: I91e8df94f4c22b2186e81d7f1016b8767d777eac
Reviewed-on: https://go-review.googlesource.com/10310
Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
Russ Cox 2015-05-21 14:35:02 -04:00 committed by Gerrit Code Review
parent 630930c35e
commit 12795c02f3
4 changed files with 52 additions and 24 deletions

View File

@ -917,14 +917,12 @@ func strnput(s string, n int) {
} }
} }
var addstrdata_name string
func addstrdata1(arg string) { func addstrdata1(arg string) {
if strings.HasPrefix(arg, "VALUE:") { i := strings.Index(arg, "=")
addstrdata(addstrdata_name, arg[6:]) if i < 0 {
} else { Exitf("-X flag requires argument of the form importpath.name=value")
addstrdata_name = arg
} }
addstrdata(arg[:i], arg[i+1:])
} }
func addstrdata(name string, value string) { func addstrdata(name string, value string) {

View File

@ -102,7 +102,7 @@ func Ldmain() {
obj.Flagint64("T", "set text segment `address`", &INITTEXT) obj.Flagint64("T", "set text segment `address`", &INITTEXT)
obj.Flagfn0("V", "print version and exit", doversion) obj.Flagfn0("V", "print version and exit", doversion)
obj.Flagcount("W", "disassemble input", &Debug['W']) obj.Flagcount("W", "disassemble input", &Debug['W'])
obj.Flagfn1("X", "set the value of a string variable; the next two arguments are its name and value", addstrdata1) obj.Flagfn1("X", "add string value `definition` of the form importpath.name=value", addstrdata1)
obj.Flagcount("Z", "clear stack frame on entry", &Debug['Z']) obj.Flagcount("Z", "clear stack frame on entry", &Debug['Z'])
obj.Flagcount("a", "disassemble output", &Debug['a']) obj.Flagcount("a", "disassemble output", &Debug['a'])
obj.Flagstr("buildid", "record `id` as Go toolchain build id", &buildid) obj.Flagstr("buildid", "record `id` as Go toolchain build id", &buildid)
@ -132,21 +132,39 @@ func Ldmain() {
obj.Flagcount("v", "print link trace", &Debug['v']) obj.Flagcount("v", "print link trace", &Debug['v'])
obj.Flagcount("w", "disable DWARF generation", &Debug['w']) obj.Flagcount("w", "disable DWARF generation", &Debug['w'])
// Clumsy hack to preserve old behavior of -X taking two arguments.
for i := 0; i < len(os.Args); i++ {
arg := os.Args[i]
if (arg == "--X" || arg == "-X") && i+2 < len(os.Args) {
os.Args[i+2] = "-X=VALUE:" + os.Args[i+2]
i += 2
} else if (strings.HasPrefix(arg, "--X=") || strings.HasPrefix(arg, "-X=")) && i+1 < len(os.Args) {
os.Args[i+1] = "-X=VALUE:" + os.Args[i+1]
i++
}
}
obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile) obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile)
obj.Flagstr("memprofile", "write memory profile to `file`", &memprofile) obj.Flagstr("memprofile", "write memory profile to `file`", &memprofile)
obj.Flagint64("memprofilerate", "set runtime.MemProfileRate to `rate`", &memprofilerate) obj.Flagint64("memprofilerate", "set runtime.MemProfileRate to `rate`", &memprofilerate)
// Clumsy hack to preserve old two-argument -X name val syntax for old scripts.
// Rewrite that syntax into new syntax -X name=val.
// TODO(rsc): Delete this hack in Go 1.6 or later.
var args []string
for i := 0; i < len(os.Args); i++ {
arg := os.Args[i]
if (arg == "-X" || arg == "--X") && i+2 < len(os.Args) && !strings.Contains(os.Args[i+1], "=") {
fmt.Fprintf(os.Stderr, "link: warning: option %s %s %s may not work in future releases; use %s %s=%s\n",
arg, os.Args[i+1], os.Args[i+2],
arg, os.Args[i+1], os.Args[i+2])
args = append(args, arg)
args = append(args, os.Args[i+1]+"="+os.Args[i+2])
i += 2
continue
}
if (strings.HasPrefix(arg, "-X=") || strings.HasPrefix(arg, "--X=")) && i+1 < len(os.Args) && strings.Count(arg, "=") == 1 {
fmt.Fprintf(os.Stderr, "link: warning: option %s %s may not work in future releases; use %s=%s\n",
arg, os.Args[i+1],
arg, os.Args[i+1])
args = append(args, arg+"="+os.Args[i+1])
i++
continue
}
args = append(args, arg)
}
os.Args = args
obj.Flagparse(usage) obj.Flagparse(usage)
startProfile() startProfile()
Ctxt.Bso = &Bso Ctxt.Bso = &Bso
Ctxt.Debugvlog = int32(Debug['v']) Ctxt.Debugvlog = int32(Debug['v'])

View File

@ -9,10 +9,12 @@
package main package main
import "fmt"
var tbd string var tbd string
var overwrite string = "dibs" var overwrite string = "dibs"
func main() { func main() {
println(tbd) fmt.Println(tbd)
println(overwrite) fmt.Println(overwrite)
} }

View File

@ -10,23 +10,33 @@
package main package main
import ( import (
"bytes"
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
) )
func main() { func main() {
test(" ") // old deprecated syntax
test("=") // new syntax
}
func test(sep string) {
// Successful run // Successful run
cmd := exec.Command("go", "run", "-ldflags=-X main.tbd hello -X main.overwrite trumped -X main.nosuchsymbol neverseen", "linkx.go") cmd := exec.Command("go", "run", "-ldflags=-X main.tbd"+sep+"hello -X main.overwrite"+sep+"trumped -X main.nosuchsymbol"+sep+"neverseen", "linkx.go")
out, err := cmd.CombinedOutput() var out, errbuf bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &errbuf
err := cmd.Run()
if err != nil { if err != nil {
fmt.Println(string(out)) fmt.Println(errbuf.String())
fmt.Println(out.String())
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
want := "hello\ntrumped\n" want := "hello\ntrumped\n"
got := string(out) got := out.String()
if got != want { if got != want {
fmt.Printf("got %q want %q\n", got, want) fmt.Printf("got %q want %q\n", got, want)
os.Exit(1) os.Exit(1)