I've read here that you can delete the built-in packages from emacs at /usr/share/emacs/25.2/lisp in order to get rid of their commands which may clutter the minibuffer every time you want to execute something via M-X or at auto-completion pop ups as you type in Emacs Lisp mode.

However, I still can see the packages that I've deleted when I run M-x package-list-packages RET in the package list marked with "built-in" status just as before. And more importantly, I still encounter their commands in the minibuffer or at auto-completion pop ups.

I've removed several dozens of packages that I don't need, their commands can't function, but they still appear. How can I completely remove the remnants of these built-in packages?

  • 2
    There might be redundant versions of packages in other directories in your load-path. Maybe try M-x find-function on an autoload function that you believe you have deleted the file for and see where it resolves?
    – ebpa
    Nov 17, 2018 at 4:47
  • That's strange, when I do use find-function, say on tetris it replies with "Cannot find the library". Nov 17, 2018 at 21:16

3 Answers 3


Short answer: You should recompile Emacs.

Long answer:

When it is compiled, the emacs executable is dumped with numerous elisp libraries pre-loaded. Amongst these libraries is the loaddefs.el library containing the autoload declarations for autoloaded functions in the standard distribution.

So (a) deleting the libraries you don't want does not delete the associated autoload declarations from loaddefs.el; and (b) even if it did that still wouldn't help you, because the emacs executable would still contain all the autoload declarations from the loaddefs.el which was generated at build time.

Strictly speaking you only need to re-dump Emacs with a modified loaddefs.el -- but in order to be able to do that you need to compile from source.

See C-hig (elisp)Building Emacs for more information.

n.b. You can remove autoload declarations at run-time; but if you want to achieve your desired result by deleting core libraries from the filesystem, then recompiling is the way to make that happen.


I can't help with what shows up when you do M+x package-list-packages, but to clean-up the command namespace (minibuffer prompt, functions available to you in lisp, etc) there are a few hacks.

The workaround

You might be seeing functions even after deletion due to residual autoload files. Firstly you need to find out what are the locations of the different packages. You can use locate-library for that. The library name is whatever you would write in a require statement if you were to use the library. For example, on my system (locate-library "org") returns "/home/user/build/org-mode/lisp/org.elc". Once you have located the libraries, you can clean up the namespace with something like this:

;; clean load-path
(setq load-path
      (delq nil (mapcar
                 (function (lambda (p)
                             (unless (string-match "lisp\\(/packages\\)?/org$" p)
;; remove property list to defeat cus-load and remove autoloads
(mapatoms (function  (lambda (s)
                       (let ((sn (symbol-name s)))
                         (when (string-match "^\\(org\\|ob\\|ox\\)\\(-.*\\)?$" sn)
                           (setplist s nil)
                           (when (eq 'autoload (car-safe s))
                             (unintern s)))))))

Source: org-mode.git/testing/org-batch-test-init.el

Background information

I use the above snippet to clean up the builtin Org mode before I setup the bleeding edge. Of course you would need to update the regular expressions according to the packages you are trying to delete.

How it works

The first part of the snippet cleans up the load-path. This is only necessary for big packages like Org that reside in their own directory in a typical Emacs distribution. For smaller modes, say a programming mode like ruby-mode, this isn't necessary.

Now to adapt the above regexes to your needs, you need to experiment a bit. Try evaluating these with C+j in the lisp interaction (*scratch*) buffer:

(locate-library "ruby-mode")
(locate-library "tetris")

Your load-path probably has these: "[..]/lisp/play", "[..]/lisp/progmodes". Unless you want to remove all progmodes, to "remove" ruby-mode you can skip the first part. On the other hand, if you want to remove all games, you might want to include the play directory. The corresponding regex then becomes: "lisp\\(/packages\\)?/play$" (the "packages" portion of the regex is an optional match, see: (info "(elisp)Syntax of Regexps")).

For the second part: clearing your namespace, you need to construct the regex based on what prefix is being used by the library in question. So for ruby-mode and tetris, you might try: "^\\(ruby\\|tetris\\)\\(-.*\\)?$". I hope this gets you started. Some experimentation in the scratch buffer is your friend :)

  • I tried to use locate-library to figure out where does tetris still come from, but it says "No library in search path". But when trying on other packages like org then it does indeed show the path to a directory in ~/.emacs.d/elpa/. Nov 17, 2018 at 21:20
  • I just tried it on my system, it pointed to a main emacs directory: "/opt/lisp/share/emacs/27.0.50/lisp/play/tetris.elc". If you have already deleted the file, maybe all you need to do is clean up the namespace with the second snippet. A thought: do not delete the files, just cleanup the namespace, unless you really want to reclaim that bit of disk space. That's what I'm doing with Org mode.
    – suvayu
    Nov 18, 2018 at 1:23
  • OK, I restored all the files that I've removed because maybe I'll really need them in the future, especially packages like ruby mode, I tend to underestimate those. Then I tried to run your snippet on both ruby mode and on tetris, it didn't work for me. I probably didn't format the strings correctly or something. I'm really willing to give up at this point and keep things as before. How should I withdraw from this question gracefully according to the community standards in case I give up or change my mind? I really appreciate all the help and the time that you guys spent on me. Nov 18, 2018 at 1:49
  • Well, one last attempt, I have expanded my answer. If this doesn't work, let it be. If you have learned something relevant from Drew's or my answers, you may upvote them without accepting either. Maybe someone else will find these answers useful.
    – suvayu
    Nov 18, 2018 at 4:19

A quick stab at an answer. Someone may provide better info.

Sounds like package-list-packages lists as "built-in" those libraries that Emacs knows it builds in. And it sounds like that is the only indication you are seeing that they exist. Unless you find some other indication, you can probably assume that package-list-packages doesn't intend that "built-in" indication as meaning that they are currently still present.

I see this comment in package.el:

;; ... Furthermore, this supports built-in packages which
;; may or may not be newer than user-specified packages.  This makes
;; it possible to upgrade Emacs and automatically disable packages
;; which have moved from external to core.  (Note though that we don't
;; currently register any of these, so this feature does not actually
;; work.)

What's more, it looks like the list of "built-ins" is set in library finder-inf.el, as the value of variable package--builtins. And that file is in fact generated by finder.el. And grepping for package--builtins shows that it isn't changed anywhere except in finder.el, function finder-compile-keywords.

So yes, it looks like you can't count on that "built-in" indication in the package-list display to reflect what is currently present at any given time.

You can use finder-compile-keywords to reset it and recompute it. It rewrites file finder-inf.el. You can try finder-compile-keywords, to see if it shows you what you really expect (e.g. no built-ins, if you really removed all of them). Grepping shows that finder-compile-keywords is used only in finder.el (e.g. package.el makes no use of it).

  • I tried to run finder-compile-keywords through eval-expression (or M-:), but it replied with "Symbol’s value as variable is void: finder-compile-keywords", did I do that properly? Nov 17, 2018 at 21:35
  • Dunno - I haven't (and won't) try it. Take a look at the code in finder.el to learn more about it. (Did you load that file?)
    – Drew
    Nov 18, 2018 at 1:55
  • I've looked into the file on GitHub when I saw your answer to see how it is being used (which parameters are being sent), however I didn't have any idea I should have loaded that before, I thought these functions are accessible as part of Emacs. I just ended up restoring all the previous files that I've removed and figured out that I rather let it be. I just asked suvayu in the other answer how to withdraw gracefully from the question at this point after it been answered because I tried both answers and I am honestly willing to give up. Nov 18, 2018 at 2:00

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.