Set variable for use in different make target - makefile

I have a make target that calls another, I want to set the variables in the make target that calls the target it depends on and pass the variables down.
FILENAME ?=
SERVICE ?=
generate-transaction-command: generate-service
FILENAME := swagger.json
SERVICE := transaction
generate-service:
#curl -s http://localhost:8181/swagger/proto/$(FILENAME) --output ./$(FILENAME)
#./gen -input ./$(FILENAME) -output ./cli/cmd/$(SERVICE).go
I want to be able to run make generate-transaction-command and then my generate-service command uses the variables set in the generate-transaction-command, at the moment it gives me this error.
FILENAME: No such file or directory
So I assume it isn't setting the variables correctly.

See Target-specific Variable Values
Example:
FILENAME ?=
SERVICE ?=
generate-transaction-command: generate-service
#echo $# recipe
# set variables for a target:
generate-transaction-command: FILENAME := swagger.json
generate-transaction-command: SERVICE := transaction
# added echo
generate-service:
#echo curl -s http://localhost:8181/swagger/proto/$(FILENAME) --output ./$(FILENAME)
#echo ./gen -input ./$(FILENAME) -output ./cli/cmd/$(SERVICE).go
output:
curl -s http://localhost:8181/swagger/proto/swagger.json --output ./swagger.json
./gen -input ./swagger.json -output ./cli/cmd/transaction.go
generate-transaction-command recipe

Related

where is the rule to build a $(obj)/subdir target in linux kernel makefile?

In linux kernel Makefile.build:
`
# To build objects in subdirs, we need to descend into the directories
$(subdir-builtin): $(obj)/%/built-in.a: $(obj)/% ;
$(subdir-modorder): $(obj)/%/modules.order: $(obj)/% ;`
the $(obj)/subdir/built-in.a depends on $(obj)/subdir prereq, but where is the rule to build $(obj)/subdir?
I assume the following rule is only for $(obj)/ directory, and can't apply for the above subdir.
`
# Build
# ---------------------------------------------------------------------------
$(obj)/: $(if $(KBUILD_BUILTIN), $(targets-for-builtin)) \
$(if $(KBUILD_MODULES), $(targets-for-modules)) \
$(subdir-ym) $(always-y)
#:`
Thanks!
I have looked up the makefile, but have not found any clue.
I already got the answer from a Linux kernel maintainer, as below:
See around line 500.
$(subdir-ym):
$(Q)$(MAKE) $(build)=$# \
need-builtin=$(if $(filter $#/built-in.a, $(subdir-builtin)),1) \
need-modorder=$(if $(filter $#/modules.order, $(subdir-modorder)),1) \
$(filter $#/%, $(single-subdir-goals))

Erratic behaviour in a makefile resulting in re-building targets

I'm using makefiles to structure a data analysis pipeline consisting of various steps such as extracting data, sampling and modelling. However, when I create an additional "upper-level" makefile (such as modelling) that depends on others, and I try to run make again (either on the new makefile or any other upper-level makefiles), it tries to re-build everything again from the lowest-level makefile targets.
In the code below I show the "lowest level" makefile and another one (makefile.sample that includes the first one):
Makefile
all:
make $(DATA_TRN)
make $(Y_TRN)
# dates
SNAP_TRN := 2019-06-18
SNAP_TST := 2019-07-24
# Targets
TARGET_CLASS = m1_vol
TARGET_SURV = m1_qty
TARGET_INIT = act_qty
END_DUR = 1
# dirs
DIR_DATA := data
DIR_CONFIG := configs
# data files for training and predict
DATA_TRN := $(DIR_DATA)/processed/churnvol_train_$(SNAP_TRN).csv
DATA_TST := $(DIR_DATA)/processed/churnvol_test_$(SNAP_TST).csv
# labels
Y_TRN := $(DIR_DATA)/processed/label_train_$(SNAP_TRN).csv
Y_TST := $(DIR_DATA)/processed/label_test_$(SNAP_TST).csv
# Config files
CONFIG_PANEL := $(DIR_CONFIG)/config_panel.yaml
CONFIG_INPUT := $(DIR_CONFIG)/config_inpute.yaml
FEATS := $(DIR_CONFIG)/featimp_churnvol.csv
# Generates a clean dataset (inputed and one hot encoded)
$(DATA_TRN): $(CONFIG_INPUT) $(FEATS) | $(DATA_DIR)
python src/_buildDataset.py --train-file $(DATA_TRN) \
--test-file $(DATA_TST) \
--train-date $(SNAP_TRN) \
--test-date $(SNAP_TST) \
--config-panel $(CONFIG_PANEL) \
--config-input $< \
--feats $(lastword $^)
$(Y_TRN): $(DATA_TRN) | $(DATA_DIR)
python src/_extractColumns.py --data $< \
--columns $(TARGET_INIT),$(TARGET_CLASS),$(TARGET_SURV) \
--file $#
clean:
-rm -rf $(DATA_TST) $(DATA_TRN) $(Y_TRN) $(Y_TST)
.PHONY: all clean
Makefile.sample.u1
include Makefile
sample:
make -f Makefile.sample.$(SAMPLE_NAME) $(DATA_TRN_SAMPLE)
SAMPLE_NAME = u1
MIN_RATIO = 0.333333 # ratio of minority class for undersampling
DATA_TRN_SAMPLE := $(DIR_DATA)/processed/churnvol_train_$(SAMPLE_NAME)_$(SNAP_TRN).csv
$(DATA_TRN_SAMPLE): $(DATA_TRN) | $(DATA_DIR)
python ./src/_generate_sample_u1.py --data-train $< \
--data-file $# \
--min-ratio $(MIN_RATIO) \
--end-feat $(TARGET_SURV) \
--end-dur $(END_DUR)
.PHONY: sample
From these 2 makefiles, I'm assuming that make only needs to rebuild $(DATA_TRN) if either $(CONFIG_INPUT) or $(FEATS) changed after $(DATA_TRN) right? The problem is that both timestamps show a previous date from the target $(DATA_TRN) and when I run make all it still rebuilds the target. src/_buildDataset.py also shows a previous date. I've tried to debug and running make $(DATA_TRN) returns a $(DATA_TRN) is up to date. message. However, when I run make $(Y_TRN) it rebuild $(DATA_TRN), which I find odd. This also means that when I run make -f Makefile.sample.u1 sample, it also goes on to rebuild $(DATA_TRN). Can someone help me figure out if I did something wrong? Or other ways to debug, such as knowing exactly what file make marked as "changed". Thank you

How to get Makefile to only produce a file name without extension?

I'm trying to make a Makefile that exports a markdown file to a pdf file that uses the same filename as the original markdown file. I used "basename" command but it produces "inputfile.md.pdf" instead of "inputfile.pdf".
Please see my code below (I adapted a code I found on the Internet. Thank you!):
.PHONY: pdf docx apa format
FILES := $(wildcard ./*.md)
pdf:
for file in $(FILES); do \
pandoc $$file \
--bibliography mypath \
--csl mypath \
--filter pandoc-citeproc \
--template eisvogel \
-o $(basename $$file).pdf; \
open $(basename $$file).pdf; \
done
Anyone who can help me? I'm a novice in Makefile (and programming in general) so any detailed help would be very much appreciated.
I also tried these codes below, but they generated an error message:
-o $(basename -s ".md" $$file).pdf; \
-o $(basename -s .md $$file).pdf; \
The way you write $(basename …) you get the basename make function. This would normally the right thing, but you try to reference a shell variable file in its argument, which is unavailable at the make layer.
In this case, it is probably easiest to call the basename shell utility, at the shell level. Therefore, you need to escape the $ to get shell substitution, like this:
-o "$$(basename -s .md $$file)".pdf; \
open "$$(basename -s .md $$file)".pdf; \
Alternatively, you could try to move the loop to the make layer, perhaps using foreach.

How can I export an environment variable in a Makefile? [duplicate]

I would like to change this Makefile:
SHELL := /bin/bash
PATH := node_modules/.bin:$(PATH)
boot:
#supervisor \
--harmony \
--watch etc,lib \
--extensions js,json \
--no-restart-on error \
lib
test:
NODE_ENV=test mocha \
--harmony \
--reporter spec \
test
clean:
#rm -rf node_modules
.PHONY: test clean
to:
SHELL := /bin/bash
PATH := node_modules/.bin:$(PATH)
boot:
#supervisor \
--harmony \
--watch etc,lib \
--extensions js,json \
--no-restart-on error \
lib
test: NODE_ENV=test
test:
mocha \
--harmony \
--reporter spec \
test
clean:
#rm -rf node_modules
.PHONY: test clean
Unfortunately the second one does not work (the node process still runs with the default NODE_ENV.
What did I miss?
Make variables are not exported into the environment of processes make invokes... by default. However you can use make's export to force them to do so. Change:
test: NODE_ENV = test
to this:
test: export NODE_ENV = test
(assuming you have a sufficiently modern version of GNU make >= 3.77 ).
As MadScientist pointed out, you can export individual variables with:
export MY_VAR = foo # Available for all targets
Or export variables for a specific target (target-specific variables):
my-target: export MY_VAR_1 = foo
my-target: export MY_VAR_2 = bar
my-target: export MY_VAR_3 = baz
my-target: dependency_1 dependency_2
echo do something
You can also specify the .EXPORT_ALL_VARIABLES target to—you guessed it!—EXPORT ALL THE THINGS!!!:
.EXPORT_ALL_VARIABLES:
MY_VAR_1 = foo
MY_VAR_2 = bar
MY_VAR_3 = baz
test:
#echo $$MY_VAR_1 $$MY_VAR_2 $$MY_VAR_3
see .EXPORT_ALL_VARIABLES
I only needed the environment variables locally to invoke my test command, here's an example setting multiple environment vars in a bash shell, and escaping the dollar sign in make.
SHELL := /bin/bash
.PHONY: test tests
test tests:
PATH=./node_modules/.bin/:$$PATH \
JSCOVERAGE=1 \
nodeunit tests/
I would re-write the original target test, taking care the needed variable is defined IN THE SAME SUB-PROCESS as the application to launch:
test:
( NODE_ENV=test mocha --harmony --reporter spec test )

How to set child process' environment variable in Makefile

I would like to change this Makefile:
SHELL := /bin/bash
PATH := node_modules/.bin:$(PATH)
boot:
#supervisor \
--harmony \
--watch etc,lib \
--extensions js,json \
--no-restart-on error \
lib
test:
NODE_ENV=test mocha \
--harmony \
--reporter spec \
test
clean:
#rm -rf node_modules
.PHONY: test clean
to:
SHELL := /bin/bash
PATH := node_modules/.bin:$(PATH)
boot:
#supervisor \
--harmony \
--watch etc,lib \
--extensions js,json \
--no-restart-on error \
lib
test: NODE_ENV=test
test:
mocha \
--harmony \
--reporter spec \
test
clean:
#rm -rf node_modules
.PHONY: test clean
Unfortunately the second one does not work (the node process still runs with the default NODE_ENV.
What did I miss?
Make variables are not exported into the environment of processes make invokes... by default. However you can use make's export to force them to do so. Change:
test: NODE_ENV = test
to this:
test: export NODE_ENV = test
(assuming you have a sufficiently modern version of GNU make >= 3.77 ).
As MadScientist pointed out, you can export individual variables with:
export MY_VAR = foo # Available for all targets
Or export variables for a specific target (target-specific variables):
my-target: export MY_VAR_1 = foo
my-target: export MY_VAR_2 = bar
my-target: export MY_VAR_3 = baz
my-target: dependency_1 dependency_2
echo do something
You can also specify the .EXPORT_ALL_VARIABLES target to—you guessed it!—EXPORT ALL THE THINGS!!!:
.EXPORT_ALL_VARIABLES:
MY_VAR_1 = foo
MY_VAR_2 = bar
MY_VAR_3 = baz
test:
#echo $$MY_VAR_1 $$MY_VAR_2 $$MY_VAR_3
see .EXPORT_ALL_VARIABLES
I only needed the environment variables locally to invoke my test command, here's an example setting multiple environment vars in a bash shell, and escaping the dollar sign in make.
SHELL := /bin/bash
.PHONY: test tests
test tests:
PATH=./node_modules/.bin/:$$PATH \
JSCOVERAGE=1 \
nodeunit tests/
I would re-write the original target test, taking care the needed variable is defined IN THE SAME SUB-PROCESS as the application to launch:
test:
( NODE_ENV=test mocha --harmony --reporter spec test )

Resources