I have a fairly simple go file which builds several internal tools written in go. It worked well until I decided to add -ldflags to my build command. The following is the snippet which formats the go build
command.
var cmd *exec.Cmd
file := fmt.Sprintf("%s.%s.%s", p.Bin, e.OS, e.Arch)
if len(p.Flags) > 0 {
ldflags := ""
for _, f := range p.Flags {
if len(ldflags) > 0 {
ldflags = ldflags + " "
}
ldflags = ldflags + f.Flag
}
ldflags = "\"" + ldflags + "\""
fmt.Println("go", "build", "-v", "-a", "-ldflags", ldflags, "-o", fmt.Sprintf("/tmp/bin/%s", file), ".")
cmd = exec.Command("go", "build", "-a", "-ldflags", ldflags, "-o", fmt.Sprintf("/tmp/bin/%s", file), ".")
} else {
fmt.Println("go", "build", "-v", "-a", "-o", fmt.Sprintf("/tmp/bin/%s", file), ".")
cmd = exec.Command("go", "build", "-a", "-o", fmt.Sprintf("/tmp/bin/%s", file), ".")
}
cmd.Dir = p.Pkg
cmd.Stdout = ioutil.Discard
cmd.Stderr = os.Stdout
cmd.Env = append(cleanEnv(),
fmt.Sprintf("GOOS=%s", e.OS),
fmt.Sprintf("GOARCH=%s", e.Arch),
)
if err := cmd.Run(); err != nil {
return err
}
My flags are defined as simple strings like so
[]flagarg{
{Flag:"-X main.buildstamp=`date -u '+%Y-%m-%d_%I:%M:%S%p'`"},
{Flag:"-X main.githash=`git rev-parse --short HEAD`"},
}
The following is the output when I print
go build -v -a -ldflags "-X main.buildstamp=`date -u
'+%Y-%m-%d_%I:%M:%S%p'` -X main.githash=`git rev-parse --short HEAD`"
-o /tmp/bin/bro.linux.amd64 .
The above command works when I paste it into my CLI but fails when I run this go build
via my go script. When I say fail I mean that it's not setting my variables githash
and buildstamp
. Copying and pasting the command does set these variables as expected.
I figured it must be something with the quotes and I have tried changing them around but I am unable to get things to work. I am starting to think I am heading down the wrong path and that it must be a better way to get this working.
The issue is likely with the command substitution (backticks); it's not doing what you expect because it's a feature of the shell, not the "go build" command.
[]flagarg{
{Flag:"-X main.buildstamp=`date -u '+%Y-%m-%d_%I:%M:%S%p'`"},
// Bash command subst ----^------------------------------^
Try executing your printed command line as a single string argument to "bash -c", e.g.:
cmd = exec.Command("bash", "-c", "go build -v -a ...")
You also might want to consider using the $(...)
form of bash command substitution (I think it's easier to read), here's a simple example to demonstrate:
cmdline := "echo \"The time is now '$(date)'!\""
out, err := exec.Command("bash", "-c", cmdline).Output()
if err != nil {
panic(err)
}
fmt.Println(string(out))
// The time is now 'Tue Aug 28 09:33:34 MDT 2018'!