57

I'm trying to include some env vars into a Makefile. The env file looks like:

FOO=bar
BAZ=quux

Note there's no leading export to each env var. If I add the leading export and just include the env file in the Makefile, everything works as it should. But I need to keep the env vars sans leading export. That prevents me from just using include envfile in the Makefile.

I've also tried doing something like this:

sed '/^#/!s/^/export /' envfile > $(BUILDDIR)/env
include $(BUILDDIR)/env

But doing that cause make to throw an error because the env file isn't there for including.

2
  • 1
    Welcome to Unix&Linux. Please state the question you have clearly. What is it exactly that you're trying to accomplish?
    – darnir
    Oct 10 '15 at 16:40
  • 1
    I'm trying to include a file that contains environment variable pairs into a Makefile so that they are available to the environment in which make is running. Oct 10 '15 at 17:06
74

I had a similar problem and landed on this thread. Another possible solution is to just do the make export command without any arguments:

include .env
export

This will export all make variables as environment variables. This behavior may or may not match all use cases, but it worked for me and didn't involve any shell scripting wizardry.

1
71

If you are using gnu make, what should work is to include the envfile file, then export the list of vars got from the same file:

#!make
include envfile
export $(shell sed 's/=.*//' envfile)

test:
        env
2
  • 11
    Thanks for this answer, it's brilliant! Although my version even works without the export $(shell... line. I just need the include line. Jan 15 '17 at 12:45
  • 2
    It's worth noting that if you have any $ in the env file make won't like them and you'll have to escape them. PASS=Pass123$ will just show up as Pass123. This answer explains the caveats pretty well. stackoverflow.com/a/44637188/3384609
    – ClintM
    May 17 '20 at 15:13
6

Preserves pre existing ENV vars

export $(shell [ ! -n "$(ENVFILE)" ] || cat $(ENVFILE) | grep -v \
    --perl-regexp '^('$$(env | sed 's/=.*//'g | tr '\n' '|')')\=')

test:
    echo $$FOO

To run

make ENVFILE=envfile test # bar

export FOO=foo
make ENVFILE=envfile test # foo
6

if your filename is .makerc then you can include it to Makefile as simple as this:

include .makerc

I prefer to add - sign before include, to suppress any warnings.

1
  • 1
    I can't verify this on make 4.2.1. without export after the include.
    – JohannesM
    Jan 25 at 18:20
5

Here is an elegant solution that does not import Make vars, but does set any environment exports for shell subprocesses. Personally I prefer to keep my profiles dynamic scripts.

export BASH_ENV=tools/sh/env.sh

There are some gotchas. Unfortunately ENV does not work, I think it should (but that's an issue with Bash, not Make). Also it really requires another line, because Make's default shell interpreter is /bin/sh.

BASH_ENV := tools/sh/env.sh
SHELL := /usr/bin/bash

On the up-side this also allows to include shell functions in Makefile scripts, but only for the recipe scripts. I don't know how other shells besides Bash fare. And there is a bit more going on. I put some testfile up as GIST.

There are plenty of complicated shell scripts imaginable. I like this Q/A best for the simple answers.

1
5

To complete previous anwswer from meuh, if you would like env file to be dynamic, you could define a setup function.

  • create env/local-dev.env,env/integ.env file with some content
  • define a method to load this
    define setup_env
        $(eval ENV_FILE := env/$(1).env)
        @echo " - setup env $(ENV_FILE)"
        $(eval include env/$(1).env)
        $(eval export sed 's/=.*//' env/$(1).env)
    endef

Then use it

    localDevEnv: ## load env/local-dev.env environment
        $(call setup_env,local-dev)
    integEnv: ## load env/integ.env environment
        $(call setup_env,integ)
1
  • 2
    Works like a charm!
    – Piotr
    Jul 2 '20 at 12:36
3

an example of how you can use .env values in Makefile

#!make
include .env

migrateinit:
    migrate create -ext sql -dir mysql/migrations -seq int_schema

migrateup:
    migrate -path mysql/migrations -database "mysql://${DB_USER_NAME}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -verbose up 1

migratedown:
    migrate -path mysql/migrations -database "mysql://${DB_USER_NAME}:${DB_PASSWORD}@tcp(${DB_HOST}:${DB_PORT})/${DB_NAME}" -verbose down 1
0

If you have bash, you can use allexport option before loading a .env file.

# sample usage:
#   $ make from-env RECIPE=another-recipe
from-env:
    bash -c 'set -o allexport; source .env; set +o allexport; make "$$RECIPE"'

another-make-recipe:
    printenv

Not the answer you're looking for? Browse other questions tagged or ask your own question.