我想要一个Go程序(在Debian/Linux/x86-64上使用Go 1.11.1)来保持构建时间戳,并用一行解释最后一行git commit.
在一个C程序(FWIW我的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 '";') >> $@
Run Code Online (Sandbox Code Playgroud)
我会把我的程序myprog与以下内容联系起来:
myprog: $(MYOBJECTS) _timestamp.c
$(LINK.c) $(MYOBJECTS) _timestamp.c -o $@
$(RM) _timestamp.c
Run Code Online (Sandbox Code Playgroud)
请注意,_timestamp.c每个成功链接都会自动删除.当然在某些标题中我会声明extern const char my_timestamp[];并且extern const char my_lastgitcommit[]:我会使用eg my_timestamp和my_lastgitcommitin main.c(并且MYOBJECTS包含main.o)
它似乎go generate可以用来以类似的方式表现.我想有一个包"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.
Run Code Online (Sandbox Code Playgroud)
但它并没有随之变化go generate,然后go install
当然,这些时间戳在编译时应该是常量字符串,并且我希望在ELF可执行文件上运行strings(1)实用程序时找到它们.
顺便说一下,我记得这个go命令的一个动机:
Go从一开始的明确目标是能够仅使用源本身中找到的信息来构建Go代码,而不需要编写makefile或makefile的许多现代替换之一.如果Go需要一个配置文件来解释如何构建你的程序,那么Go就会失败.
所以我仍然希望单独进入源代码,而不需要额外的构建配置.
换句话说,我想在每个构建时生成类似于以下内容的Go文件:
// generated timestamp.go file
package timestamp
var Buildtime = "Tue 30 Oct 2018 09:39:01 AM MET";
var Buildlastgitcommit = "7fde394b60bc adding timestamp.go"
Run Code Online (Sandbox Code Playgroud)
该Buildtime字符串由date +%c.生成.该Buildlastgitcommit字符串可能由类似于我的_timestamp.cmake规则所做的命令生成.
我需要这些字符串是常量的并且内置由Go构建生成的ELF可执行文件(我更喜欢通过常用命令完成,或者没有额外的参数go build或任何其他构建自动化工具,或者某种方式使其失败如果忘记了强制性的论点,那就建立起来;因此atanayel的答案是不够的.所以我希望strings(1)实用程序在可执行文件中快速找到这些字符串.并且应该在某种文件中配置此类文件的生成,而不需要额外的构建器参数.
我可以考虑改用其他一些,去友好,构建自动化系统(但似乎即使有GB我不能轻易做什么,我想:快速生成一些简单的.go在每个构建文件).但我不明白为什么在Go程序中使用生成的 Go文件如此困难.生成简单的代码遵循Unix哲学,并且已经实践了几十年(例如,见旧的yacc程序启发的goyacc).
注意:明确提到的理由go generate是:
构建像Unix
make(1)实用程序这样的通用构建系统并不是本提议的目标.
然后
一旦确定了问题,作者就会将生成的文件提交到源存储库,
(这不是我的用例)
PS.我只关心POSIX系统; 我真的不在乎我的Go软件是否无法在Windows上构建.而且我倾向于认为(与go命令动机的解释相反),在我的特定情况下,我确实需要一些构建自动化工具.在我的bastawigo玩具项目(GPLv3 +)中,我正在使用make(驾驶go命令)
您可以使用构建时标志来执行此操作.这个答案解释了它用于不同的用例,但是你的用例与之相同.你应该做这样的事情.
buildTimego 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.请参阅我链接的答案以获得更好的解释.
正如提到的其他答案一样,您可以在构建时将所需的值注入二进制文件。
例如,如果我们有以下包变量:
// build flags
var (
BuildTime string
CommitHash string
GoVersion string
GitTag string
)
Run Code Online (Sandbox Code Playgroud)
然后,我们可以使用以下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
Run Code Online (Sandbox Code Playgroud)
示例代码来自此仓库。