Reputation: 635
I spent the better part of the day trying to figure this out. I want to use make for building a golang project with different os targets and multiple binaries. I think I want to use gnu make
My stripped down Makefile looks like:
main= mailworker websocket worker init
os= linux freebsd darwin
all: $(main)
$(main): ensure_build_path
@echo "Build $@ Version: $(GIT_REV)"
@rm -rf $(BUILD_PREFIX)/$@
GO111MODULE=on GOARCH=amd64 $(GO) build -o $(BUILD_PREFIX)/$@ ./bin/$@/[email protected]
Now I want to add GOOS=$(os)
to the build command / generate a target for every main X os combination. My test / lern Makefile looks like:
os=linux freebsd darwin
main=mailworker websocket worker init
define build_template =
t:=$(addprefix $(1), $(2))
$(info $(t))
$(t):
@echo $(1) $(2) $$@
endef
$(foreach P, $(main), $(foreach O, $(os), $(eval $$(call build_template, $O, $P))) )
There are at least a dozen variants of this I tried. I think my main problem is how to declare t
inside the template. I tried many "concat" methods I found regarding make. Also :=
or =
for t. I think :=
is the right one. But I am not sure about anything anymore ;)
To be clear, I want make to "generate" targets that look like:
mailworker_linux:
GO111MODULE=on GOOS=linux GOARCH=amd64 $(GO) build mailworker
mailworker_darwin:
GO111MODULE=on GOOS=darwin GOARCH=amd64 $(GO) build mailworker
Is this a good way doing this? And if so, where is my misunderstanding.
Thanks a lot
Upvotes: 6
Views: 1196
Reputation: 100936
You have a few problems here. First, your invocation of call
is incorrect: you're escaping it which means it won't be expanded before it's given to eval; that's not correct it must be expanded first. You want:
..., $(eval $(call build_template,$P,$O))..
(only one $
before call
.
Second, the rule for a variable you define that is used with an eval/call pair is that every macro expansion inside that variable that you want to be seen by the eval has to be escaped. In your case you did escape the $@
as $$@
which is good, but the other thing you need to escape is uses of $(t)
, because that variable is not set until the eval
sets it. So you need to write your variable like this:
define build_template =
t := $(addprefix $(1)_,$(2))
$$(info $$(t))
$$(t):
@echo $(1) $(2) $$@
endef
(I added in the missing _
to your addprefix
). It doesn't matter whether you use =
or :=
here; they both work the same since you're always using this variable in an immediate-expansion context.
As an aside, it seems everyone runs straight to eval and call which are extremely powerful but also difficult to use and understand. An alternative that uses more straightforward make constructs might be something like this:
getmain = $(word 1,$(subst _, ,$@))
getos = $(word 2,$(subst _, ,$@))
TARGETS := $(foreach P,$(main),$(addprefix $P_,$(os)))
all: $(TARGETS)
$(TARGETS): %:
@echo $(getmain) $(getos) $@
Upvotes: 6