Makefile targets as cross product of two lists
up vote
1
down vote
favorite
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/$@/$@.go
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
makefile gnu-make
add a comment |
up vote
1
down vote
favorite
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/$@/$@.go
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
makefile gnu-make
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
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/$@/$@.go
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
makefile gnu-make
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/$@/$@.go
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
makefile gnu-make
makefile gnu-make
asked Nov 9 at 12:20
huehnerhose
16115
16115
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
4
down vote
accepted
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) $@
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
accepted
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) $@
add a comment |
up vote
4
down vote
accepted
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) $@
add a comment |
up vote
4
down vote
accepted
up vote
4
down vote
accepted
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) $@
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) $@
answered Nov 9 at 13:58
MadScientist
45.3k44865
45.3k44865
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53225617%2fmakefile-targets-as-cross-product-of-two-lists%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown