Batch-generate Emacs byte-compiled files in a custom directory - emacs

I'm generating byte-compiled files (*.elc) using the batch-byte-compile function. This function writes out the *.elc files in the same directory as the *.el files.
How can I have Emacs generate the byte-compiled files in a different directory?
An ideal solution would be operational system agnostic.

Emacs uses byte-compile-dest-file to generate a compiled file name from a source file name. That function delegates to customizable variable byte-compile-dest-file-function if non-nil.
So you can simply define it. Something like this:
(defun my-byte-compile-dest-file (source-file)
(concat (file-name-directory source-file)
"prefix-"
(file-name-base source-file)
"-compiled"))
(setq byte-compile-dest-file-function 'my-byte-compile-dest-file)

Related

Let .emacs.d behaves just like a .d folder

I want to solve my “.emacs bankruptcy” issue, and I've gone through
https://help.ubuntu.com/community/EmacsHowto
http://www.emacswiki.org/emacs/DotEmacsBankruptcy
http://www.emacswiki.org/emacs/DotEmacsDotD
http://www.gnu.org/software/emacs/manual/html_node/emacs/Init-File.html
and it is still unclear to me whether the .emacs.d folder is the solution. I.e., whether it will behave just like a normal .d folder, e.g., /etc/profile.d/, where you drop you scripts and they will be picked up by the system auto-magically. Please confirm.
If not, can someone give me a script that does that, or give me a solution please?
Thanks
The essential content of my ~/.emacs file is:
(require 'cl)
(loop for src in (directory-files "~/.emacs.d" 'full-path "[0-9].*\\.el$") do
(let ((byte (concat src "c")))
(when (file-newer-than-file-p src byte)
(byte-compile-file src))
(message "Loading %s.elc" byte)
(load-file byte)))
It loads configuration files from ~/.emacs.d which start with a number. If the source file (extension .el) is newer than the byte-compiled version (extension .elc) then it byte-compiles the source. Afterwards it loads the byte compiled file.
Here's my ~/.emacs:
;; base dirs
(defvar dropbox.d "~/Dropbox/")
(defvar emacs.d (concat dropbox.d "source/site-lisp/"))
;; load path
(add-to-list 'load-path emacs.d)
(defun add-subdirs-to-load-path (dir)
(let ((default-directory dir))
(normal-top-level-add-subdirs-to-load-path)))
(add-subdirs-to-load-path emacs.d)
(load "init")
All my other scripts are loaded by ~/Dropbox/source/site-lisp/init.el
and are themselves located in ~/Dropbox/source/site-lisp.
That's how I have the same config on multiple machines.
And here's how .../site-lisp/hooks.el is loaded from init.el:
(load "hooks")
My init.el is about 100 lines, .emacs about 20 lines.
The rest 8000 lines of scripts are sliced into around 20 files.
~/.emacs.d/ does not work like /etc/profile.d/ or /etc/modules-load.d/ or similar directories, i.e. Emacs does not automatically load any Emacs Lisp file in this directory.
In fact, Emacs explicitly advises against placing Emacs Lisp libraries in ~/.emacs.d/. The byte compiler emits a warning if you add ~/.emacs.d/ to the load-path.
Instead, create a new sub-directory, e.g. ~/.emacs.d/lisp. Add this directory to your load-path explicitly, with the following code in init.el:
(add-to-list 'load-path (locate-user-emacs-file "lisp"))
Then, place your Emacs Lisp files in this directory, e.g. ~/.emacs.d/lisp/foo.el, and load them in your init.el:
(load "foo" nil 'no-message)
The best approach to avoid the dreaded .emacs bankruptcy is to actually avoid large customizations! Most notably, try to avoid any custom functions and commands.
Instead, try to a find an ELPA package that comes closest to what you want, and either try to get used to it, or customize it to your needs. If you don't find any, first try to write your own and distribute it on Github, Marmalade or MELPA.
Don't be afraid of maintaining a package in the public. You'll have to maintain your customization anyway, whether in your init.el or not, so you can just as well let other Emacs users help you with this job.
Adding code to your init.el should be your very last resort!

How to declare the location of Emacs's init file as a variable

I use Emacs across a few computers (Linux and Windows boxes) with my .emacs.d synced via ownCloud: .emacs (in ~ or Appdata) just loads {ownCloud directory}/.emacs.d/init.el.
My question is, how do I get that path to the init.el as variable dependent on the OS/username.
For example, the README on the Zenburn theme requires your init includes
(add-to-list 'custom-theme-load-path "~/.emacs.d/themes/")
But as the path from my home directory and .emacs.d varies between machines, this won't work.
I was thinking of something like this to remedy it:
(add-to-list 'custom-theme-load-path "{THE DIRECTORY THAT CONTAINS THIS INIT FILE}/themes/")
Can this be done? I'm only a fortnight's into using Emacs, so don't bite too hard :P
The variable system-type determines between Linux and Windows machines. The variable user-login-name is self explanatory. I use these to load different files depending on which machine I'm in.
(if (eq system-type 'gnu/linux)
(when (string= user-login-name "home user name")
(load-file "/path/to/file"))
(when (string= user-login-name "work user name")
(load-file "/path/to/other-file")))
Honestly though, this is more appropriate for miscellaneous configurations. I wouldn't recommend using this to change your emacs directory location.
Instead, create symlinks on each machine in order to pretend your emacs directory is in the standard place. (I've been doing this on 4 different machines for a couple of years now, and it's going well).
Finally, to answer your last question. The init file already is a variable, and its name is user-init-file. To extract the directory it's located in just do
(file-name-directory user-init-file)
There is user-emacs-directory variable.

Is this a proper Emacs (24.3.2) lisp style to load user .el files from .emacs?

I have several .el files within my "~/.emacs.d" directory and I added the following lines to my .emacs file to load them at startup:
(let ((base "~/.emacs.d/")
(files '("user.el" "erlang.el" "sbcl-slime.el"))
(bfload (lambda (file) (load (expand-file-name (concat base file))))))
(mapcar bfload files))
It works, but is this proper Emacs Lisp style? How can this be improved, please?
First, don't put your .el files directly into ~/.emacs.d (Emacs puts various files in there, and they're not expected to be Elisp packages). You can put them into ~/.emacs.d/pkgs for example, instead.
How 'bout:
(dolist (file '("user.el" "erlang.el" "sbcl-slime.el"))
(load (expand-file-name file "~/.emacs.d/pkgs"))
You can mix Stefan's excellent suggestions of moving those files to a separate directory with init-loader https://github.com/emacs-jp/init-loader
You will have a couple of extra perks (auto byte-compiling the files) and you won't need to maintain the file list (just move/create a file in that directory).
Based on Stefan's example, I only add a file-exists-p:
(dolist (file '("user.el" "erlang.el" "sbcl-slime.el"))
(let ((f (expand-file-name file "~/.emacs.d/pkgs")))
(if (file-exists-p f)
(load f))))
I think, this is the version I will use.

How to have Emacs create backup files with OpenVMS Files-11 style file names with version numbers?

This SO answer about .emacs file contains:
;; keep backup files neatly out of the way in .~/
(setq backup-directory-alist '(("." . ".~")))
which triggered an idea that it would be handy if Emacs would create backup files using the OpenVMS Files-11 version naming. For example, x.txt;3 or x.txt.3 for the third version of x.txt
Check out this article: http://www.glindra.org/doc/version_number.html. The short story is to add:
(setq version-control t)
in your .emacs file.

How to install a Emacs plugin (many times it's a .el file) on Windows platform?

I'm new to Emacs. I found many emacs plugins are released as an .el file. I'm not sure how to install them. Can I just put them in my emacs installation directory?
After placing it, say myplugin.el to your ~/.emacs.d/ directory, add the following in your .emacs file:
(add-to-list 'load-path "~/.emacs.d/")
(load "myplugin.el")
Also, in many cases you would need the following instead of the second line:
(require 'myplugin)
In any case, you should consult the documentation of the package you are trying to install on which one you should use.
If you are unsure where your ~ directory is, you may see it by typing C-x d ~/ and pressing Enter.
As already stated, you'll need the location of the file to be in Emacs' load path.
Read the comments at the top of the file to see if it has any particular installation or usage instructions. Authors often provide this information, and there isn't one single correct way to do it, so it's sensible to look.
Failing that, if the file contains a (provide 'some-name) line (typically at the end of the file), then you would be expected to use (require 'some-name) to load it.
You may also wish to byte-compile the library for speed (but that's a different question).
Many times, an emacs plugin will consist of a directory of elisp files that need to be accessible from the load path. A simple way to ensure that all individual elisp files as well as subdirectories of elisp files are included in the load path and accessible is to do something similar to the following:
Create a directory called ~/.emacs.d/site-lisp.
Install any single elisp files in the ~/.emacs.d/site-lisp directory.
Install any packages that consist of multiple elisp files in a subdirectory under your ~/.emacs.d/site-lisp directory.
Add the following code to your ~/.emacs file to ensure that Emacs "sees" all the elisp files that you have installed:
(add-to-list 'load-path "~/.emacs.d/site-lisp")
(progn (cd "~/.emacs.d/site-lisp")
(normal-top-level-add-subdirs-to-load-path))
This will ensure that all elisp files that are located either in either the ~/.emacs.d/site-lisp directory or in a subdirectory under that directory are accessible.
Some supplementary information:
MATLAB.el comes from http://matlab-emacs.sourceforge.net/
On windows, use the load path that looks like this:
(add-to-list 'load-path' "C:\\Dropbox\\Portable\\emacs\\matlab-emacs")
If you want FULL MATLAB functionality you should use:
;;MATLAB Mode:
(add-to-list 'load-path' "C:\\Dropbox\\Portable\\emacs\\matlab-emacs")
(require 'matlab-load)
if you just want to edit text files:
;;MATLAB Mode:
(add-to-list 'load-path' "C:\\Dropbox\\Portable\\emacs\\matlab-emacs")
(autoload 'matlab-mode "matlab" "Enter MATLAB mode." t)
(setq auto-mode-alist (cons '("\\.m\\'" . matlab-mode) auto-mode-alist))
(autoload 'matlab-shell "matlab" "Interactive MATLAB mode." t)