88

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.

  • 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. – Michael Irwin Oct 10 '15 at 17:06

8 Answers8

115

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.

Brock
  • 1,151
  • 5
    For better backwards compatibility, I'd recommend setting the .EXPORT_ALL_VARIABLES: special target instead of using the export directive, as described here in the manual: https://www.gnu.org/software/make/manual/html_node/Variables_002fRecursion.html – jlucktay Jul 26 '21 at 05:27
  • 1
    Worth to hint that if .env doesn't exist, GNU Make will raise .env: No such file or directory – artu-hnrq Sep 01 '22 at 15:28
  • Doing -include .env will prevent the error, which may or may not be the desired result – Marvin Feb 23 '23 at 19:30
  • This creates infinite recursion in make >=4.4 as in this exmample: https://github.com/photoprism/photoprism/discussions/3790 How do you fix it? – tback Oct 04 '23 at 18:47
95

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
meuh
  • 51,383
  • 13
    Thanks for this answer, it's brilliant! Although my version even works without the export $(shell... line. I just need the include line. – Dawngerpony Jan 15 '17 at 12:45
  • 6
    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. https://stackoverflow.com/a/44637188/3384609 – ClintM May 17 '20 at 15:13
10

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)
boly38
  • 349
10

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

8

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
mildog8
  • 181
7

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.

mpe
  • 106
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.

holms
  • 276
1

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