makefile cd into dir and execute command - makefile

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.

Related

Makefile to "activate" Python virtual environment

I'm trying to create a Python virtual environment with a Makefile and also activate it once the make command finishes to ease things for the user. Apparently, this is not possible because "a child process can not alter the parent's environment." I was wondering if there's any workaround for this. This is part of my Makefile so far:
.PHONY: create-venv venv
.DEFAULT_GOAL := all
SHELL=/bin/bash
CPUTYPE = $(shell uname -m | sed "s/\\ /_/g")
SYSTYPE = $(shell uname -s)
BUILDDIR = build/$(SYSTYPE)-$(CPUTYPE)
VENV_NAME?=venv
VENV_DIR=$(BUILDDIR)/${VENV_NAME}
VENV_BIN=$(shell pwd)/${VENV_DIR}/bin
VENV_ACTIVATE=. ${VENV_BIN}/activate
PYTHON=${VENV_BIN}/python3
create-venv:
test -d $(BUILDDIR) || mkdir -p $(BUILDDIR)
which python3 || apt install -y python3 python3-pip
test -d $(VENV_DIR) || python3 -m venv $(VENV_DIR)
venv: ${VENV_BIN}/activate
${VENV_BIN}/activate: setup.py
test -d $(VENV_DIR) || make create-venv
${PYTHON} -m pip install -r requirements.txt
touch $(VENV_BIN)/activate
source ${VENV_BIN}/activate # <- doesn't work
. ${VENV_BIN}/activate # <- doesn't work either
You can activate the environment and run a shell in the activated env:
. ${VENV_BIN}/activate && exec bash
(Please note it must be in one line to be run in one shell; exec is used to replace the shell with a new one.)
When you finish working with the environment you exit and then the Makefile is finished.
You could do something like this.
It relies on your looking at the activate script and seeing what env vars it sets, so it is totally ugly.
$(eval $(shell source $(PYTHON3_VENV)/bin/activate && echo "export PATH := $$PATH; export PYTHONHOME := $$PYTHONHOME; export VIRTUAL_ENV := $$VIRTUAL_ENV" ))

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 )

Using make file to create package inside nodejs monorepo

I'm new to using Makefile(s) and I'd like to create a command make package <PACKAGE_NAME>.
And I'd like it to run the following:
mkdir $PACKAGE_NAME
cd $PACKAGE_NAME
npm init -y
mkdir src
mkdir lib
mkdir test
I'm a little confused if I should put this in a shell script or If I can just have this directly in the make file itself (which is preferable), and I also am unsure how to have arguments in a Makefile.
This will do it:
package:
mkdir $(PACKAGE_NAME)
cd $(PACKAGE_NAME) ; npm init -y ; mkdir src lib test
The whitespace at the beginning of line 2 is a TAB, not four spaces. Likewise line 3.

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 )

Why does following makefile rebuilt target "build" everytime

I have the following code to untar all the files in a directory and move it to build directory. If I call make multiple times, it tries to execute "build" target everytime even if build directory already exists. Has anyone comes across this?
I found this question but it is not the same.
Makefile always running target
OS: Ubuntu 12.04
Program: GNU Make 3.81
build: mkBuildDir untar
chmod 700 build
.PHONY: mkBuildDir untar
mkBuildDir:
mkdir build
untar: *.tar.gz
for prefix in *.tar.gz; do \
tar xvf $$prefix --directory=build; \
done
clean:
rm -Rf build
This is pretty much the same as the question you've linked. You never create a file called mkBuildDir, so it's always out-of-date, so build is always out of date.
Your mkBuildDir target isn't doing anything useful (though I presume this is a cut-down makefile). If instead you did
# it'd be better to list the TARFILES explicitly, though this will probably work
TARFILES=`ls *.tar.gz`
all: build untar
build: $(TARFILES)
test -d build || mkdir build
chmod 700 build
for prefix in $(TARFILES); do \
tar xvf $$prefix --directory=build; \
done
clean:
rm -Rf build
that would probably accomplish what you're looking for.
Having too many phony targets in a Makefile is usually a makefile 'code smell'. They are rarely the best/idiomatic way of doing things.

Resources