Wednesday, February 7, 2024

[SOLVED] Shell variable in a string passed with -ldflags to the Go compiler is not expanded

Issue

I'm trying to get a simple build bash script to work and can't get the date as an argument. What am I missing here? Thanks.

#!/bin/bash
buildDate=$(date)
go build -ldflags='-X main.buildTimestamp=$buildDate' main.go

Output: Build: $buildDate


Solution

To quote the documentation on a POSIX-compatible shell:

2.2.2 Single-Quotes

Enclosing characters in single-quotes ( '' ) shall preserve the literal value of each character within the single-quotes. A single-quote cannot occur within single-quotes.

So, in your particular case, bash breaks the go build … command into words and performs string substitution before actually executing the command.

As per string substitution rules, the text enclosed with single quotes is taken literally, so after the expansion the shell looks up the go command and executes it pasing it the tree resulting arguments, which are, in order: build, -ldflags=-X main.buildTimestamp=$buildDate and main.go.

Since the Go toolchain does not invoke shell anywhere in its course of work, the literal text $buildDate gets passed unmodified to the compiler.

If the format of your build date does not include whitespace, the easiest fix is to just replace the single quotes with double quotes.

If you need to embed spaces in there, it gets a little bit more tricky but not too much — to cite the output of go build help:

The -asmflags, -gccgoflags, -gcflags, and -ldflags flags accept a space-separated list of arguments to pass to an underlying tool during the build. To embed spaces in an element in the list, surround it with either single or double quotes. <…>

In other words, the command-line argument parser considers pairs of "s and 's to implement argument grouping, and in your case you could do

go build -ldflags="-X main.buildTimestamp='$buildDate'" main.go

so that the shell strips out the outer double quotes and substitutes $buildDate for its value — as per the rules of string substitution for the case of double quotes.
Hence, if your build date format includes spaces, like in, say, Tue, 12 May 2020 20:53:16 +0300, the go command would receive the following three arguments, in order: build, -ldflags=-X main.buildTimestamp='Tue, 12 May 2020 20:53:16 +0300' and main.go, and would take care of those single quotes by itself.



Answered By - kostix
Answer Checked By - Timothy Miller (WPSolving Admin)