11

I have a makefile like this:

setup:
  setenv var1 "$(var1)"; \
  setenv var2 "$(var2)";

task1: setup
  source task1.csh

task2: setup
  source task2.csh

I call the makefile using this command:

make var1=value1 var2=value2 task1

I would like environment variables var1 and var2 to be visible in task1.csh and task2.csh, but I haven't been able to do so unless I change the makefile to:

task1:
  setenv var1 "$(var1)"; \
  setenv var2 "$(var2)"; \
  source task1.csh

task2:
  setenv var1 "$(var1)"; \
  setenv var2 "$(var2)"; \
  source task2.csh

Why the first method doesn't work and how can I fix it?

jww
  • 97,681
  • 90
  • 411
  • 885
Ari
  • 7,251
  • 11
  • 40
  • 70
  • 4
    I should point out that you should never use csh to write make recipes in. csh is too broken a shell to use with make. Really it's too broken of a shell to script in, period, but that's a discussion for another day. – MadScientist Dec 04 '14 at 01:01
  • 1
    @MadScientist: I'm actually using tcsh. Still not recommended? – Ari Dec 04 '14 at 01:24
  • 3
    Csh and all variants including tcsh are not recommended. Use them as interactive shells if you want (personally I don't since (a) modern Bourne shells like bash have all the interactive features of any csh/derivative and more, and (b) I write a lot of little one-liner scripts on the command line in my interactive shell, but whatever), but csh is fundamentally broken for use with make; see http://lists.gnu.org/archive/html/bug-make/2010-12/msg00017.html and for more details about scripting in csh in general see http://www-uxsup.csx.cam.ac.uk/misc/csh.html – MadScientist Dec 04 '14 at 01:30
  • Possible duplicate of [How to set environment variable in Makefile](http://stackoverflow.com/questions/23843106/how-to-set-environment-variable-in-makefile) – Eugen Konkov Jan 04 '17 at 16:55
  • Possible duplicate of [Setting environment variable in Makefile](https://stackoverflow.com/q/8022586/608639) – jww Jun 07 '18 at 23:20

1 Answers1

18

That doesn't work because every line in a makefile rule is run in its own shell instance.

From the GNU make manual:

When it is time to execute recipes to update a target, they are executed by invoking a new sub-shell for each line of the recipe, unless the .ONESHELL special target is in effect (see Using One Shell) (In practice, make may take shortcuts that do not affect the results.)

Please note: this implies that setting shell variables and invoking shell commands such as cd that set a context local to each process will not affect the following lines in the recipe.2 If you want to use cd to affect the next statement, put both statements in a single recipe line

So you can do it the way you listed or you can export the variables from make and they will be in the environment of the sub-shells already.

export var1 = value1
export var1 = value2

task1: source task1.csh

task2: source task2.csh

As a side note why are you sourcing those scripts instead of just running them directly (./task1.sh)?

(I'm assuming you set SHELL = csh or similar in your makefile to make this work at all already.)

Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
  • Thank you! Actually, I set the values of var1 and var2 upon calling the makefile (edited the question). Under this condition, using `export var1 = $(var1)` causes a recursive error. – Ari Dec 03 '14 at 22:43
  • 1
    @Ari Just use `export var1`, without an assignment, if your variable is already assigned. – Louis Dec 03 '14 at 23:40
  • @Ari Variables assigned on the command line should *automatically* be in the environment of the commands run by make. You shouldn't need to do anything to have that work. See section 5.7.2 of the manual. – Etan Reisner Dec 04 '14 at 02:22
  • @EtanReisner: C shell doesn't support environment variables set on the command line — it isn't like the Bourne-derived shells. – Jonathan Leffler Dec 04 '14 at 03:47
  • @JonathanLeffler As I understood the section of the make manual I mentioned when make reads a variable on its command line (as an argument not as a bourne-shell pre-command variable) it automatically exports the variable. That should work for csh/etc. if `export` in the makefile does. – Etan Reisner Dec 04 '14 at 03:49
  • Hmmm...it seems that GNU `make` does do that, and POSIX requires it. Way back, many years (decades) ago, when I was writing a variant of `make`, I didn't uncover that behaviour in my research, which either means that my research was incomplete or that long ago setting the environment wasn't supported. Also, I was assuming you were thinking of the `var=value make …` notation rather than `make var=value …` notation — but that was a mitsake. – Jonathan Leffler Dec 04 '14 at 04:01
  • 1
    One thing to remember about using .ONESHELL directive - it is available only in GNU make 3.82+. E.g. Ubuntu 12.04, CentOS 6.6 come with GNU make 3.81. – tvar0g Dec 04 '14 at 11:22