I have a relatively large elisp file which starts becoming hard to maintain and I am going to split it into smaller files.

However, for my use case, it would be still convenient to have a single byte-compiled file (because I use it on other systems and it is simpler to copy a single file).

Of course, I could concatenate all source files into a single foo.el file and compile the latter.
Before going this way, I would like to know if there is already a function along the lines of:

(byte-compile-directory foo-dir foo)

generating a single foo.elc from sources in foo-dir.

  • 1
    Why do you want to have a single byte-compiled file? If it's because you only want to require one thing, I think there are better ways of doing that. – Qudit Mar 3 '18 at 21:58
  • @Qudit: Well, for a proper package, you update it on a public repo and you install it on the targets. If you update it, you re-upload and reinstall it on the targets. But, for 2/3 boxes, a single file elc is much more convenient. You can put it on a USB pen and execute emacs --batch -l .... And you can generate a single el file to copy along the elc, better than nx2 files. I find this more practical than zipping/unizipping, but it might be a matter of taste. – antonio Mar 3 '18 at 22:34

There is byte-recompile-directory, but it does not produce a single .elc.

Consider putting the files in the same, dedicated directory; using byte-recompile-directory (after compiling each file once); and zipping the directory into a .zip archive or similar.

One command to byte-compile everything, one command to zip it all up, and one to unzip it at the destination. (And you can combine the first two commands into one.)


Another possibility below.

se-load-chunks loads all the source files set by the variable chunks.
se-make-single creates the unique source file single.el.
se-compile both makes a single.el and compiles it.

;; compile-help.el

(defvar chunks (list "chunk1"

(defun se-load-chunks ()
  (mapc (lambda (file) (load (se-make-path file))) chunks))

(defun se-make-single ()
  (let ((dst (se-make-path "single")))
    (if (file-exists-p dst) (delete-file dst))
    (mapc (lambda (chunk)
            (se-append-file dst (se-make-path chunk)))

(defun se-compile ()
  (byte-compile-file (se-make-path "single")))

(defun se-append-file (destination source)      
  (with-temp-buffer (insert-file-contents source)
        (append-to-file (point-min) (point-max) destination)))

(defun se-make-path (file)
  "Make path"
  (expand-file-name (concat file ".el")))

Update Implemented @Basil suggestions.
Replace the se- namespace with something better.

  • Some nits: 1) cd and compile are existing core commands; it is bad to recommend overriding them. Please consider using a namespace prefix as suggested in (elisp) Coding Conventions. 2) You should call (expand-file-name (concat file ".el")) instead of concating path components. 3) You can simplify append-file by using the built-in append-to-file. 4) Please fix the indentation - tabs don't have the same width on SE as they do in Emacs. – Basil Mar 3 '18 at 13:05
  • @Basil: Thanks for your valuable feedback. Everything has been implemented – antonio Mar 3 '18 at 21:41
  • Thanks. You can probably still make se-append-file more performant via (with-temp-buffer (insert-file-contents source) (append-to-file (point-min) (point-max) destination)); buffer positions are always quicker than building strings. How is se-load-chunks relevant? – Basil Mar 3 '18 at 21:49
  • @Basil: Fixing that too. As regards, se-load, the idea is that se-compile comes into play only when you are finished and you want to execute the elc file elsewhere or want to keep a single el for archiving or sharing. However, when developing and modifying constituent el files, instead of opening and using eval-buffer for each file, you use se-load. If there is a unique entry point for the package, say (main), that should be called by se-load too. – antonio Mar 3 '18 at 22:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.