4

I'm trying to set a variable at load-time:

# emacs --eval '(defvar myvar t)'

Now, in this session, if I C-h v myvar RET I get a nice t. But if I put (message "MYVAR: %s" myvar) in my init file, I get a nasty Symbol's value as variable is void: myvar.

I also tried

# emacs --eval '(eval-after-load (defvar myvar t) t)'

Without luck. (How) can I set (Elisp, not ENV) variables on the command line that I can use in my init file?

Drew
  • 75,699
  • 9
  • 109
  • 225
yPhil
  • 963
  • 5
  • 22

3 Answers3

5

This doesn't work because command line options are processed after the init file. This allows the command line to refer to functions and variables defined or loaded in the init file, and allows the init file to declare additional options.

To run something before the init file, you can force a different load order:

# emacs --no-init-file --eval '(defvar myvar t)' --load ~/.emacs.d/init.el
  • --no-init-file / -q: Don't load the init file.
  • --eval ... --load ...: Define the variable and then load the init file.
xuchunyang
  • 14,302
  • 1
  • 18
  • 39
3

I found a hackish way: I start Emacs like this:

# emacs -alt

Then in my init file:

(if (member "-alt" command-line-args)
    (let ((default-directory "~/src/elisp-test/"))
      (normal-top-level-add-subdirs-to-load-path)
      (message "Atlternate conf"))
  (message "Regular conf"))

It works, at the cost of a command-line-1: Unknown option -alt warning in the messages buffer, but it's only for test purposes, so it's OK.

EDIT: @xuchunyang's answer is obviously the right one :

emacs -q --eval '(setq -alt t)' --load ~/.emacs

And in my .emacs:

(defvar -alt nil)

(if -alt
    (let ((default-directory "~/src/elisp-test/"))
      (normal-top-level-add-subdirs-to-load-path)
      (...)
      (message "Alternate conf"))
  (message "Regular conf"))
yPhil
  • 963
  • 5
  • 22
  • 1
    Rather than manually exploring `command-line-args`, add a new entry to [`command-switch-alist`](https://www.gnu.org/software/emacs/manual/html_node/elisp/Command_002dLine-Arguments.html#index-command_002dswitch_002dalist-4690) or [`command-line-functions`](https://www.gnu.org/software/emacs/manual/html_node/elisp/Command_002dLine-Arguments.html#index-command_002dline_002dfunctions-4697). That way Emacs will know that the option has been parsed. – Gilles 'SO- stop being evil' Jul 30 '17 at 22:38
2

As I did not get the top voted answer to work (I suppose I have to write additional code to read out the defvar variable) I use environment variables

First I did create a wrapper batch or bash file:

rem Set environment variable to first argument of batch script
SET SOMEFILE=%1
cd C:\somedir
C:\somedir\runemacs.exe --load ./something.el

Within my something.el I can access the environment variable

(find-file (getenv "SOMEFILE"))

This has some drawbacks. For example if you want to run mutliple concurrent emacs instances. But for my simple requirements it works flawless.

1u1u
  • 21
  • 1