Possible to make go not touch the built file if it builds purely from cache?

104 views
Skip to first unread message

Glen Huang

unread,
Apr 15, 2020, 7:55:14 AM4/15/20
to golang-nuts
I have a makefile where upon a new go binary being built, it builds some other stuff that is not go related.

The go binary is unconditionally built with a FORCE prerequisite, so the go build command always runs, but that command always updates the output binary, which leads to downstream being unnecessarily built.

Is there a way to tell go not to touch the output file if it builds purely from the cache?

Currently it prevents me from using a makefile, and I don't really feel like sidestepping go's cache system by manually listing all go files and have the makefile functions as a cache, besides, it's really difficult to correctly list dependencies if the module is big and the binary being built only depends on a subset. 

Brian Candler

unread,
Apr 15, 2020, 9:00:32 AM4/15/20
to golang-nuts
Not answering your question directly, but some large projects (e.g. gVisor) are using bazel, which may solve this for you.  Specifically supports multi-language builds.

Ian Lance Taylor

unread,
Apr 15, 2020, 4:09:27 PM4/15/20
to Glen Huang, golang-nuts
Updating the binary is intentional, so that `go build` has consistent behavior.

The way to handle this in a Makefile is to use the move-if-change
dance, which looks more or less like

real-target: stamp-target; @true
stamp-target: ...
go build -o temporary-target ...
if cmp temporary-target real-target; then \
rm temporary-target; \
else \
mv temporary-target real-target
fi
touch stamp-target

With this technique stamp-target will be rebuilt if any of its
dependencies change, and real-target will be rebuilt only if the build
generated a file that was different in some way.

Ian

Glen Huang

unread,
Apr 15, 2020, 9:37:51 PM4/15/20
to golang-nuts
I end up using "go list" to list dependencies, and rely on the makefile to cache builds, for the binary runs in docker and the host machine is a Mac, and cross compiling with race detector enable doesn't seem to easy in this case. Previously I had to give race detector up to use go build directly.

move-if-change sounds like a good approach, will come in handy when there is no need to cross compile, thanks for the tip.

Personal

unread,
Apr 15, 2020, 10:25:03 PM4/15/20
to Glen Huang, golang-nuts
If the source code is not large enough, I think this will works,

```
CMD_SRC :=$(shell go list -f '{{ $$dir := .Dir }}{{ range .GoFiles }} {{ $$dir }}/{{.}} {{end}}' $(CMD_DIR))

your/binary: $(CMD_SRC)
go build ./cmd/binary
```

Glen Huang

unread,
Apr 16, 2020, 1:57:07 AM4/16/20
to golang-nuts
Thanks, as mentioned in the previous reply, this is what I end up using.
Reply all
Reply to author
Forward
0 new messages