6

I'm using emacs for many different projects. For some of them, I need, for example, different entries in $PATH, or different $MAKEFLAGS, whatever, you name it...

I thought this would be possible somehow like this in .dir-locals:

((c++-mode
  (c-basic-offset . 4)
  (tab-width . 4)
  (eval progn
          (make-local-variable 'process-environment)
          (setenv "gna" "gnagna3")))
 (c-mode
  (c-basic-offset . 4)
  (tab-width . 4)))

Bit with this approach, "gna" is set in all buffers.

What am I missing?

Drew
  • 75,699
  • 9
  • 109
  • 225
Markus
  • 471
  • 2
  • 12

1 Answers1

7

Both the buffer-local and the global variable are initially pointing to the same cons cell / list. If setenv pushes a new value to the front of the list, that would only be reflected in the local list value (the global value would effectively point to the cdr of the local value) in which case your code should work as desired; however if setenv is modifying an existing element further down the list, that change will be reflected in both values.

You can avoid this by making a copy of the list.

(eval . (progn
          (make-local-variable 'process-environment)
          (setq process-environment (copy-sequence process-environment))
          (setenv "gna" "gnagna3")))

You could also shorten that by using setq-local

phils
  • 48,657
  • 3
  • 76
  • 115
  • Of course, if you do this, it will cause problems, at least it did for me. If you start a shell from a buffer that has a buffer-local process-environment the sell will not inherit your changes to the process-environment. See https://emacs.stackexchange.com/questions/45563/have-shell-inherit-buffer-local-process-environment. – Benilda Key Nov 14 '18 at 05:17
  • 2
    That is because in general non-file-visiting buffers do not see directory-local variables. So it's not that this approach is "causing problems", but rather that it's not having any effect in the shell buffer. I've added an answer to the linked question. – phils Nov 14 '18 at 06:01