我希望在Go程序中(在Debian / Linux / x86-64上使用Go 1.11.1)保持构建时间戳,并在一行中说明最后一个git commit
。
在C程序中(我的bismon项目正在做非常相似的事情),我只会生成一些_timestamp.c
文件,例如Makefile
的食谱,例如:
_timestamp.c:
date +'const char my_timestamp[]='%c';%n' > $@
(echo -n 'const char my_lastgitcommit[]="'; \
git log --format=oneline --abbrev=12 --abbrev-commit -q | head -1 \
| tr -d '\n\r\f\"\\\\' ; echo '";') >> $@
,然后将程序myprog
与以下内容链接:
myprog: $(MYOBJECTS) _timestamp.c
$(LINK.c) $(MYOBJECTS) _timestamp.c -o $@
$(RM) _timestamp.c
请注意,_timestamp.c
会在每个成功链接时自动删除。当然,在某些标头中,我会声明extern const char my_timestamp[];
和extern const char my_lastgitcommit[]:
并使用例如{{1}中的my_timestamp
和my_lastgitcommit
(并且main.c
包含MYOBJECTS
)
看起来go generate
可以以类似的方式使用。我想使用一个软件包main.o
来定义两个字符串全局变量"timestamp"
和timestamp.My_timestamp
,但我不完全了解该怎么做。
我尝试添加一些timestamp.My_gitcommit
文件
timestamp/timestamp.go
但是它并没有随着package timestamp
//go:generate date +'var My_timestamp = "%c"%n'
// Code generated - DO NOT EDIT.
然后go generate
改变
当然,这些时间戳在编译时应该是常量字符串,我希望在ELF可执行文件上运行strings(1)实用程序时会找到它们。
顺便说一句,我记得the go
command的动机之一:
从一开始,Go的一个明确目标就是能够仅使用在源代码本身中找到的信息来构建Go代码,而无需编写makefile或许多现代的makefile替代之一。如果Go需要一个配置文件来说明如何构建程序,那么Go将会失败。
因此,我仍然希望单独将一些内容放到源代码中,而无需进行额外的构建。
换句话说,我想在每次构建时都生成一个类似于以下内容的Go文件:
go install
// generated timestamp.go file
package timestamp
var Buildtime = "Tue 30 Oct 2018 09:39:01 AM MET";
var Buildlastgitcommit = "7fde394b60bc adding timestamp.go"
字符串由Buildtime
生成。 date +%c
字符串可能由类似于我的Buildlastgitcommit
make规则执行的命令生成。
我需要这些字符串是恒定的,并内置在Go构建中生成的ELF可执行文件中(我更希望通过通常命令来完成,或者不使用{{1} }或任何其他构建自动化工具,或者如果忘记了必需参数,则通过某种方式使构建失败;因此atanayel's answer是不够的)。因此,我希望strings(1)实用程序能够在可执行文件中快速找到这些字符串。并且此类文件的生成应以某种类型的文件进行配置,而不需要为构建器添加额外的参数。
我可以考虑切换到其他的 Go-friendly {3}}系统(但是,即使使用build automation,我也无法轻松完成自己想要的工作:每次构建时都会快速生成一些简单的_timestamp.c
文件)。但是我不明白为什么在Go程序中使用生成的 Go文件如此困难。 gb之后便是生成简单的代码,并且已经有数十年的实践了(例如,受旧的Unix philosophy程序启发,参见goyacc)。
NB:yacc明确提到:
构建像Unix
go build
实用程序这样的通用构建系统不是本提案的目标。
及以后的
问题解决后,作者将生成的文件提交到源存储库中,
(这不是我的用例)
PS。我只关心POSIX系统;我真的不在乎我的Go软件是否不能在Windows上构建。而且我倾向于认为(与rationale for go generate
的解释相反),在我的特定情况下,我要做需要一些构建自动化工具。在我的go
command motivation玩具项目(GPLv3 +)中,我正在使用.go
(驱动make(1)
命令)
答案 0 :(得分:6)
您可以使用构建时间标志来执行此操作。 This answer针对不同的用例进行了解释,但您的使用情况与之相同。 你应该做这样的事情。
buildTime
go build -ldflags='-X buildTime="My build time output from a command"'
buildTime
是常量,等于My build time output from a command
。My build time output froma a command
。请参阅我链接的答案以获得更好的解释。
答案 1 :(得分:3)
正如提到的其他答案一样,您可以在构建时将所需的值注入二进制文件。
例如,如果我们具有以下程序包变量:
// build flags
var (
BuildTime string
CommitHash string
GoVersion string
GitTag string
)
然后我们可以使用以下bash脚本填充它们:
#!/bin/sh
clear
TRG_PKG='main'
BUILD_TIME=$(date +"%Y%m%d.%H%M%S")
CommitHash=N/A
GoVersion=N/A
GitTag=N/A
if [[ $(go version) =~ [0-9]+\.[0-9]+\.[0-9]+ ]];
then
GoVersion=${BASH_REMATCH[0]}
fi
GV=$(git tag || echo 'N/A')
if [[ $GV =~ [^[:space:]]+ ]];
then
GitTag=${BASH_REMATCH[0]}
fi
GH=$(git log -1 --pretty=format:%h || echo 'N/A')
if [[ GH =~ 'fatal' ]];
then
CommitHash=N/A
else
CommitHash=$GH
fi
FLAG="-X $TRG_PKG.BuildTime=$BUILD_TIME"
FLAG="$FLAG -X $TRG_PKG.CommitHash=$CommitHash"
FLAG="$FLAG -X $TRG_PKG.GoVersion=$GoVersion"
FLAG="$FLAG -X $TRG_PKG.GitTag=$GitTag"
if [[ $1 =~ '-i' ]];
then
echo 'go install'
go install -v -ldflags "$FLAG"
else
echo 'go build'
go build -v -ldflags "$FLAG"
fi
示例代码来自此repo。
答案 2 :(得分:0)
export LAST_BUILD=$(date +"%T") ; go build ...
Os.Getenv("LAST_BUILD")