How can I load environment variables from another file in my makefile? - bash

I want to set environment variables when I run my makefile commands however ideally the variables will be stored in another file.
./Makefile
_init_dev:
. ./config/dev-env
diff-dev: _init_dev
cdk diff
deploy-dev: _init_dev
cdk deploy
./config/dev-env
export HELLO_CDK_DEPLOY_ENVIRONMENT=dev
First I tried to use source to load in the vars however this failed with the message:
make: source: Command not found
I understand this is because make runs sh and not bash.
I then tried to add . in front of my config file to attempt to load the variables that way.
Neither approach has worked. When I run my cdk command I can see from the output the environment variable has not been set.
Can anyone advise on a way to get this to work?

Every recipe line in a makefile is run in its own shell. Environment variables modify the current shell, but those changes go away when the shell exits. So, it's completely impossible for one recipe to set environment variables that are then visible inside a different recipe.
If you want these variables available you must source them in each recipe line, like this:
diff-dev:
. ./config/dev-env && cdk diff
deploy-dev:
. ./config/dev-env && cdk deploy
You can put this into a variable, like:
CDK = . ./config/dev-env && cdk
diff-dev:
$(CDK) diff
deploy-dev:
$(CDK) deploy
Alternatively if your dev-env file is a simple-enough format (such as the one you show) that it works as both a makefile AND a shell script, you could include it:
include ./config/dev-env
diff-dev:
cdk diff
deploy-dev:
cdk deploy
But this will only work for very limited contents of dev-env (basically simple assignment of variables to static strings).

Related

Makefile - when running shell commands the output doesn't have line breaks

I'm editing a makefile that ran a lot of sh scripts, and i just added one that runs a terraform command.
When i use directly the .SH file (or the command manually in console, the output is OK, but if i ran it inside the makefile, the output is all together, without spacing or line breaks.
Is there any way to fix this?
PFB commands and outputs.
runcommands.sh (it ran as ./runcommands.sh init/plan/etc)
terraform $1
output:
Terraform initialized in an empty directory!
The directory has no Terraform configuration files. You may begin
working with Terraform immediately by creating Terraform configuration
files.
Makefile:
plan:
$(shell ./runcommands.sh init)
output:
Terraform initialized in an empty directory! The directory has no
Terraform configuration files. You may begin working with Terraform
immediately by creating Terraform configuration files.
The recipe:
plan:
$(shell ./runcommands.sh init)
does not do what you seem to think it does. The $(shell ...) syntax executes the command and builds a string. Because of its location in the Makefile, that string is then executed as a command. You almost certainly do not want the output of ./runcommands.sh to be executed. You want:
plan:
./runcommands.sh init

Local variables not working in a gnu Makefile?

I am running make on macOS and it is not pleased with any local variables . Take this snippet intended to get the full path to the directory of the Makefile script
setup_for_run:
mkfile_path=$(abspath $(lastword $(MAKEFILE_LIST)))
mkfile_dir=$(dir $(mkfile_path))
echo "scriptdir=$(SCRIPT_DIR)"
export PATH=$($(SCRIPT_DIR)/.venv/bin:$(PATH))
The result of make setup_for_run is:
$make setup_for_run
mkfile_path=/Users/steve/git/hercl/Makefile
mkfile_dir=
echo "scriptdir="
scriptdir=
export PATH=
So we see that none of the local variables are operational. What is the way to get them activated in the gnu make installed by default on macOS ?
Make runs each command in a recipe in its own shell (unless declaring .ONESHELL). Any modified state such as variables is cleared for each command. And, any variables set are never communicated outside make. For this purpose you're more likely to want to source a bash script.
Make are for making files from other files.
There are several alternatives to set the variables:
# Global scope
VARIABLE := myglobal
# Target specific
mytarget: VARIABLE := targetspecific
# Prefix the command
myprefix:
VARIABLE=prefix env

Export variable declared in script.sh and Import the value in mupltiple Makefiles

I am trying to create something like a global variable that I will use in order to make my project easy to deploy for other developers.
I would like to have an .sh file where there is a variable defining the location of the project.
Later on I want to export this variable and make it accessable in every makefile that I am creating so that I can use this design to keep everything constant and in one place.
This is an example of what I am trying to build:
Creating and exporting the variables in script.sh:
#!/bin/bash
DIRECTORY='some path value here'
Importing the values in multiple Makefiles:
# start script and fetch the value
VAR := $(shell ./script.sh | sed -n '/^result: /s/^.*: //p')
all:
#echo VAR=$(VAR)
I would like to see how other people are dealing with the same problem.
Being a better developer is my goal here. :)
Feedback always welcomed.
Environment variables exported in the shell are visible from make, so in a shell script like this:
#!/bin/sh
VAR=value
export VAR
make $*
The Makefile will start with VAR defined to value. That's one way to get variables from a shell script into make.
If you don't want the shell script to run make, you can have a user source it:
$ source script.sh
$ make
The variables set in the script will be visible to make this way too.
Or course there doesn't seem to be any reason you need a shell script here. Stick your configuration into a fragment of a Makefile (which would look almost exactly like your shell script, but not use quotes for multiple word values) and then include Makefile.inc in your main makefile.
Also note that syntax like this:
#!/bin/sh or another commment
VAR=value
export VAR
It equally valid included in a Makefile or sourced into a shell script. So sometimes it's possible to use the same include file in both places!

Running a script inside a makefile

I want to run a script inside a makefile like this
all: a b
a:
cd ~/trials; \
. ./sx.sh
b:
echo $(bn)
sx.sh do this
export bn=1
I don't see the variable in my terminal while issuing make command. My aim is to run a script before compiling my project for those script specific settings.
You can't assume that the commands issued by make are all processed by the same instantiation of the shell. Make does not open a shell and feed it commands one-by-one and nor does it save the commands into a file and then feed it into a shell. It usually spawns a shell for each command like this:
$(SHELL) -c 'cd ~/trials; . ./sx.sh'
which means you cannot alter the environment and have it inherited by later commands.
The best way is to use make variables to store the specifics you wish to pass to the commands and use those variables in appropriate places.

OpenVPN Source vars not working on debian

I have to create a script to setup an OpenVPN server automatically.
In this script I need to source the vars file in /etc/openvpn/easy-rsa/
But when I'm executing the following script in the /etc/openvpn/easy-rsa/ folder (with chmod 775 on the script and vars file) it says "xxxx.sh: 3: xxxx.sh: source: not found:"
#!/bin/bash
source ./vars
When I write . ./vars, it works, but then if I want to do a ./clean-all it says :
Please source the vars script first (i.e. "source ./vars")
Make sure you have edited it to reflect your configuration.
When I do the ./clean-all in the same script than the . ./vars, it works.
Thanks for your help (and sorry for my bad english :/)
When you source (or .) a file, all the commands inside it are read and executed - this includes variable assignments. However, when a variable assignment takes place, it takes place only for the current shell. When you run a script, a subshell is created - so any variables inside the script are only visible within the subshell, not the parent (calling) shell. This is why it works when you have run source and clean-all within the same script, it should also work if you do both from the command line, ie:
$ . /etc/openvpn/easy-rsa/vars
$ /etc/openvpn/easy-rsa/clean-all

Resources