4

How can I correctly set environment variables in a makefile on Windows? I get an error about CreateProcess.

C:\>make.exe -f build.makefile start
export MALLOC_PERTURB_=110
process_begin: CreateProcess(NULL, export MALLOC_PERTURB_=110, ...) failed.
make (e=2): The system cannot find the file specified.
c:\testmake.makefile:4: recipe for target 'start' failed
make: *** [start] Error 2

START: 
    export NODE_ENV=110
    echo $(NODE_ENV)
user6033608
  • 93
  • 1
  • 1
  • 7
  • 2
    Possible duplicate of [How to set environment variable in Makefile](https://stackoverflow.com/questions/23843106/how-to-set-environment-variable-in-makefile) – Victor Sergienko Feb 09 '19 at 22:18

1 Answers1

5

Your question isn't entirely clear but there are a number of obvious things wrong there.

First off you are running make under Windows but writing recipes as if they were shell scripts. That's not the case on Windows (by default at least).

So export is being attempted to be run as an external command which is failing (hence the error message about CreateProcess failing).

You also don't show us the target that is actually throwing that error.

Additionally you are expecting the export and assignment on the first line of the recipe to be in effect for the second line in the recipe body (for the start target).

But that isn't the case. Each line in a makefile target's recipe runs in an independent environment. So the export and assignment on the first line of the START target's recipe doesn't affect the second line.

To do that you need to use one long line or use the .ONESHELL feature of recent versions of make.

Additionally, you are using $(NODE_ENV) in your recipe expecting that to be the shell variable you previously set. And even ignoring the previously stated problem that isn't correct.

make is going to expand $(NODE_ENV) as a make variable before it even runs the recipe at all. You meant ${NODE_ENV} or $NODE_ENV for a shell variable. That said for a make recipe you actually need to escape the $ because ${NODE_ENV} is also a valid make variable expansion. So you need $${NODE_ENV} or $$NODE_ENV there.

Put together you end up with this (assuming you have a shell somewhere to use).

SHELL := /path/to/your/shell

START:
        export NODE_ENV=110; \
        echo "$${NODE_ENV}"

(though you don't actually need export at that point but that's a different issue entirely).

But if you don't have a shell to use then you get to use cmd.exe and I'm not sure what the equivalent of export there is (though as I just said you don't need it for this) and you end up with something like this (entirely untested):

START:
        NODE_ENV=110; \
        echo %NODE_ENV%
Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
  • This was the solution. .ONESHELL: START: set NODE_ENV=110 @echo %NODE_ENV% – user6033608 Mar 11 '16 at 19:37
  • Wow. ONESHELL improved the build speed a lot! Thanks! – user6033608 Mar 11 '16 at 19:42
  • 1
    Yes, `.ONESHELL` will do that since it uses *far* fewer shell invocations. That said it also drastically changes the semantics of the build (since failures on any given line won't abort the build immediately) at least not without "modif[ing] .SHELLFLAGS to add the -e option to the shell which will cause any failure anywhere in the command line to cause the shell to fail" and `-e` isn't entirely reliable and has a number of caveats. – Etan Reisner Mar 11 '16 at 20:28