Does anyone else have this problem? You’ve made some changes to one of your start-up emacs files. Then you fire up a new instance of emacs to check if your new feature works. However, none of your changes seem to have made a difference. So you spend some time looking into what you did wrong. And finally you realise – Emacs loads compiled emacs-lisp code in preference to uncompiled code, even when the uncompiled code is newer.
True story – this has happened to me more than a couple of times. The fifth second time I decided to fix it. I’ve come up with a solution that I’m fairly happy with: Emacs is started from a script called run_emacs.sh
that runs another script called compile.sh
(I’ve done it this way so I can run compile.sh independently).
#!/bin/sh $HOME/emacs-files/compile.sh emacs $*
compile.sh
calls batch-byte-compile-if-not-done
.
#!/bin/sh cd $HOME/emacs-files emacs --batch \ --eval "(add-to-list 'load-path (expand-file-name \"~/emacs-files\"))" \ --eval "(add-to-list 'load-path (expand-file-name \"~/emacs-files/org-xxx\"))" \ --eval "(batch-byte-compile-if-not-done)" *.el
And last but not least I alias emacs to run_emacs.sh
.
$ alias emacs='$HOME/emacs-files/run_emacs.sh'
Yes, many times. My .emacs auto compiles when I save it but this
invariably breaks when I’ve updated via git. Surely it must be
possible to fix it in the .emacs itself rather than messing about with
scripting. I wonder if buffer-file-type is t when emacs is evaluating
.emacs.elc?
Happened to me all the time. Now, I use this code from the emacs starter kit
(add-hook ’emacs-lisp-mode-hook ‘esk-remove-elc-on-save)
(defun esk-remove-elc-on-save ()
“If you’re saving an elisp file, likely the .elc is no longer valid.”
(make-local-variable ‘after-save-hook)
(add-hook ‘after-save-hook
(lambda ()
(if (file-exists-p (concat buffer-file-name “c”))
(delete-file (concat buffer-file-name “c”))))))
This catches most of my changes but not when I update via git. I still have to remember to blow away my elc files and regenerate.
« emacs loads compiled emacs-lisp code in preference to uncompiled code, even when the uncompiled code is newer. »
This is a bug and therefore should be reported. M-x report-emacs-bug RET 🙂
@Alex – auto-compile on save is a nice solution. But yes, I see how it wouldn’t save you from source code control updates.
@Seth – Yep, deleting the elc on save is another good idea. I didn’t think of that either.
@Paul – Oh yes, I guess this _is_ a bug. I didn’t think of it like that. But surely people have been caught out by this for ages?
Indeed if you look at startup.el it warns about it:
;; If we loaded a compiled file, set
;; `user-init-file’ to the source version if that
;; exists.
(when (and user-init-file
(equal (file-name-extension user-init-file)
“elc”))
(let* ((source (file-name-sans-extension user-init-file))
(alt (concat source “.el”)))
(setq source (cond ((file-exists-p alt) alt)
((file-exists-p source) source)
(t nil)))
(when source
(when (file-newer-than-file-p source user-init-file)
(message “Warning: %s is newer than %s”
source user-init-file)
(sit-for 1))
(setq user-init-file source))))
In fact user-init-file is set to “/home/alex/.emacs.elc” in my current
session at the start of the .emacs.elc evaluation even though the
startup code has tweaked it to “/home/alex/.emacs” at the end so I
suspect it should be work round-able.
I have raised a bug report as suggested.
Apologies for continually spamming the comments. Bug raised as #2577:
http://emacsbugs.donarmstrong.com/cgi-bin/bugreport.cgi?bug=2577
Hey Alex, no worries. It’s all good information (and thanks for reporting the bug) so carry on!
Thanks
Unfortunately the Emacs maintainers don’t consider this a bug. There’s some obscure justification for always preferring the compiled version, but it’s harmful to most users.
The remove-elc-on-save hook is the best I’ve come up with, but it’s not perfect. Perhaps the “Warning: %s is newer than %s” function could be defavdice’d to do the right thing?
Hi Phil,
I see that they say that uncompiled code is work in progress. I suppose that is a view, but I’d be interested to know which causes more annoyance.
I really like that idea 🙂
In my .emacs file I check if it needs to be updated, and if it does it puts a hook in find-file-hooks to ask me if I want to recompile (sometimes I don’t for whatever reason). After the first invocation it removes itself from the hook so I don’t have to see it again.
;; To overcome the fact that that we can’t bytecompile the .emacs while it is being read
(when (file-newer-than-file-p “~/.emacs” “~/.emacs.elc”)
(defun byte-compile-dotemacs-if-needed ()
(when (y-or-n-p “byte-compiling .emacs to update .emacs.elc? “)
(byte-compile-file “~/.emacs”))
(remove-hook ‘find-file-hooks ‘byte-compile-dotemacs-if-needed))
(add-hook ‘find-file-hooks ‘byte-compile-dotemacs-if-needed))
Hi Ivan,
Does this mean that it only checks when you first load the .emacs file by which time you’ve loaded the out of date .elc? Maybe you can adopt the compile with a script solution and then you won’t have that problem.
Yes, it will have loaded the out-of-date file, but it will then load the newly compiled file, so 99% of the time it just means that my startup is slower. I rarely have anything that I need to NOT get loaded, and if I do, I just exit and start emacs again.
I actually kind of like that it reminds me that I forgot to compile it (or I have changes from version control), and gives me the option to not spend the time compiling if I don’t want to.
Isn’t this only the case if you actually load your .emacs, or do you always load your .emacs (or does the hook automatically trigger at start-up?)
And what if you’ve changed a defvar, does that work correctly or do you not defvar in your .emacs?
I guess I didn’t explain too well. It puts itself in the find-file-hooks so that it runs the first time I open a file. If I had known about the after-init-hook (I learned about it a few hours ago) I would have put it there (I am moving it there as we speak). And no, defvar doesn’t work, which is one of the drawbacks.
Ah yes, that makes sense – it runs when you load _any_ file. Any reason you don’t want to use the compile-script suggested in the post? It would seem to resolve all problems that have been mentioned.
I tend to keep the bulk of my initialization in a file outside my .emacs, for a couple of reasons:
1. It’s easier to put under revision control — I’ve never found a great solution for source code control of .* files in the homedir;
2. It’s easier to share across machines.
Now .emacs holds only that stuff that is in flux and is OK to be uncompiled (well, mostly!).
If one takes this kind of approach, I think .emacs could check the other files it loads to see if the compiled versions are up-to-date….
My configuration lives in a bunch of files under ~/emacs-files/. My .emacs only consists of lines that look like this:
(add-to-list ‘load-path …)
(require …)
I still like using my compile script as described above, not to compile the .emacs but to compile everything under ~/emacs-files.
And sometimes you want to apply your changes to .emacs immediately. This is the utility function that I use to manage my .emacs compilation:
(defun dotemacs ()
“Byte compiles and loads the .emacs file.”
(interactive)
(progn
(byte-compile-file “~/.emacs”)
(load-file “~/.emacs.elc”)))
[…] didn’t want to settle for that. My solution was to recompile my emacs lisp files prior to running […]
The EmacsWiki page on auto recompiling is well worth reading:
http://emacswiki.org/emacs/AutoRecompile
Looks like there will be a new option to prefer the newer file in 24.4. The last message in the bug report is this –
——————
From: Glenn Morris <rgm gnu.org>
To: 2577 debbugs.gnu.org
Subject: Re: bug#2577: startup.el should choose .emacs ahead of .emacs.elc if
.emacs is newer
Date: Tue, 17 Dec 2013 22:35:45 -0500
Emacs 24.4 will have a `load-prefer-newer’ option.
Since the default is nil, it does not help with loading the init file,
if the init file is where you set it non-nil…
Personally I think it would be fine to eg simply bind it non-nil around
loading of the init file, but people seem to feel quite strongly about
this issue, and I’m not going to argue it.
http://debbugs.gnu.org/cgi-bin/bugreport.cgi?bug=2577