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

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 )

Related

How To Make Makefile with .PHONY Targets that work on Windows (Windows_NT) and Mac (Darwin)

So I found a link that shows I should use the following, but perhaps my logic is wrong within the Makefile. I need to use the Makefile for testing purposes to work on both Mac and Windows. The image is fine and the docker container works, I am just trying to make use of the fact that in Linux/Mac \ can be used to shorten the commands, whereas in Windows you have to use the backtick (`).
Example:
.PHONY: validate-lookml
validate-lookml:
UNAME_S=$(shell uname -s)
ifeq ($(UNAME), Linux)
docker run --rm -it -e LOOKER_BASE_URL=${LOOKER_BASE_URL} \
-e LOOKER_CLIENTID=${LOOKER_CLIENTID} \
-e LOOKER_CLIENT_SECRET=${LOOKER_CLIENTSECRET} mirantis/mirantis_spectacles \
lookml \
--base-url ${LOOKER_BASE_URL} \
--client-id ${LOOKER_CLIENTID} \
--client-secret ${LOOKER_CLIENTSECRET} \
--project ${PROJECT} \
--branch ${BRANCH}
endif
ifeq ($(UNAME), Darwin)
docker run --rm -it -e LOOKER_BASE_URL=${LOOKER_BASE_URL} \
-e LOOKER_CLIENTID=${LOOKER_CLIENTID} \
-e LOOKER_CLIENT_SECRET=${LOOKER_CLIENTSECRET} mirantis/mirantis_spectacles \
lookml \
--base-url ${LOOKER_BASE_URL} \
--client-id ${LOOKER_CLIENTID} \
--client-secret ${LOOKER_CLIENTSECRET} \
--project ${PROJECT} \
--branch ${BRANCH}
endif
ifeq ($(UNAME), Windows_NT)
docker run --rm -it -e LOOKER_BASE_URL=${LOOKER_BASE_URL} `
-e LOOKER_CLIENTID=${LOOKER_CLIENTID} `
-e LOOKER_CLIENT_SECRET=${LOOKER_CLIENTSECRET} mirantis/mirantis_spectacles `
lookml `
--base-url ${LOOKER_BASE_URL} `
--client-id ${LOOKER_CLIENTID} `
--client-secret ${LOOKER_CLIENTSECRET} `
--project ${PROJECT} `
--branch ${BRANCH}
endif
Unfortunately, it doesn't work on Windows, and I need my Makefile to support analysts on Windows Laptops:
Error:
C:\Users\richa\Git\Mirantis\dataops-looker [main ≡ +0 ~1 -0 !]> make -s validate-lookml
process_begin: CreateProcess(NULL, uname -s, ...) failed.
Makefile:9: pipe: No error
process_begin: CreateProcess(NULL, uname -s, ...) failed.
Makefile:12: pipe: No error
process_begin: CreateProcess(NULL, uname -s, ...) failed.
Makefile:15: pipe: No error
usage: spectacles lookml [-h] [--config-file CONFIG_FILE] --base-url BASE_URL
--client-id CLIENT_ID --client-secret CLIENT_SECRET
[--port PORT] [--api-version API_VERSION] [-v]
[--log-dir LOG_DIR] [--do-not-track]
[--severity {success,info,warning,error,fatal}]
--project PROJECT [--branch BRANCH]
[--remote-reset | --commit-ref COMMIT_REF | --pin-imports PIN_IMPORTS [PIN_IMPORTS ...]]
spectacles lookml: error: argument --base-url: expected one argument
make: *** [Makefile:40: validate-lookml] Error 2
Much confusion here.
A makefile consists of lines written in two completely different languages: one is the make language, and the other is the shell. You cannot send make operations to the shell, and you cannot run (directly) shell commands in make.
Make tells the difference between these two by use of the TAB character. Lines that are not indented with TAB are parsed by make, and lines that are indented with TAB are given to the shell. So, in your makefile:
validate-lookml:
UNAME_S=$(shell uname -s)
ifeq ($(UNAME), Linux)
docker run --rm -it -e LOOKER_BASE_URL=${LOOKER_BASE_URL} \
this is not right because the first two indented lines here are make commands, and the third is a shell command. You should write this like:
UNAME_S := $(shell uname -s)
validate-lookml:
ifeq ($(UNAME), Linux)
docker run --rm -it -e LOOKER_BASE_URL=${LOOKER_BASE_URL} \
...
endif
ifeq ($(UNAME), Darwin)
...
etc.
But, there is no uname command on Windows so when you run this it won't work, that's why you're getting the error process_begin: CreateProcess(NULL, uname -s, ...) failed. If you have GNU make 4.0 or better I recommend that you look at the MAKE_HOST variable and use that instead of trying to run uname.
Finally, you don't have to worry about the backslash difference, because make will parse all the backslashes and remove them on its own BEFORE it starts the shell. So just use backslashes to continue all the lines in your recipe and it will work the same way on all different platforms.

Set variable for use in different make target

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

makefile cd into dir and execute command

I have several AWS lambda functions which i want to build and deploy and have the following Makefile
#!/bin/bash
#SHELL:=/bin/bash --login
functions = $(sort $(dir $(wildcard */)))
define deploy
cd $1 && npm deploy-dev
endef
deploy:
$(foreach fn,$(functions),$(eval $(call deploy,$(fn))))
Basically each function is a node.js project that has the following entry in the package.json
"scripts": {
"deploy-dev": "npm build && rm -rf node_modules && npm i --production --legacy-bundling && AWS_PROFILE=dev SLS_DEBUG=* sls deploy --stage dev --region us-east-1"
cd into dir and running npm deploy-dev works as expected, but how to automate this?
i get an error:
➜ new_ingest git:(feature/organise) ✗ make deploy (git)-[feature/organise]
Makefile:11: *** missing separator. Stop.
For purposes of finding the problem, we can reduce it to one function, changing this:
deploy:
$(foreach fn,$(functions),$(eval $(call deploy,$(fn))))
to this:
deploy:
$(eval $(call deploy,foo))
(where foo/ is one of your directories.) Now we can see the problem. The $(call ...) part expands to cd foo && npm deploy-dev. It's a command to be passed to the shell, mot to be interpreted by Make. So when you tell Make to eval it, Make says "this is gibberish". If you remove the eval, it works.
Restoring the foreach causes a problem: all of the commands are concatenated into a single line (cd foo && npm deploy-dev cd bar && npm deploy-dev ...). To solve this you could hack deploy:
define deploy
cd $(1) && pwd ; cd - ;
endef
or you could revise the scheme to give each function its own rule.

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 )

make test doesn't do anything for mocha tests

I'm following this example: http://brianstoner.com/blog/testing-in-nodejs-with-mocha/
I defined a Makefile in my root directory:
REPORTER = dot
test:
#NODE_ENV=test ./node_modules/.bin/mocha \
--reporter $(REPORTER) \
test-w:
#NODE_ENV=test ./node_modules/.bin/mocha \
--reporter $(REPORTER) \
--watch
.PHONY: test test-w
But when I run 'make test' it says "make: Nothing to be done for `test'."
Turns out Makefiles are tab-sensitive -- and those were clobbered when I cut-n-paste the file...
In vi, i turned on tabs and spacing to fix it:
vi Makefile
:set list
Now you can retab the file and ensure you are doing it correctly.

Resources