7

If I have required a dynamic module in emacs, and then modify the source and rebuild it, how do I get emacs to reload the new module? I have not been able to just require it again. The only thing that works so far is to give the module a new name.

For example, here is a little c code that makes a module (adapted from http://nullprogram.com/blog/2016/11/05/)

#include "emacs-module.h"

int plugin_is_GPL_compatible;

int
emacs_module_init(struct emacs_runtime *ert)
{
    emacs_env *env = ert->get_environment(ert);
    emacs_value message = env->intern(env, "message");
    const char hi[] = "Hello, cruel world!";
    emacs_value string = env->make_string(env, hi, sizeof(hi) - 1);
    env->funcall(env, message, 1, &string);
    return 0;
}

You compile it with:

gcc -Wall  -fPIC -c hello.c
gcc -shared -o hello.so hello.o

Then load (note in this case we have to load it because we did not provide any feature, so require does not work here) it with (assuming it is not built on your path):

(add-to-list 'load-path "path to hello.so")
(load "hello")

And you will get a message in Messages of "Hello, cruel world!"

Now, you decide to change the message to "Hello, world!" you recompile the c code and reload it, but you still get the old message.

You can restart emacs to get it to work, or start a second emacs for testing as suggested, but this is not something I usually have to do when writing elisp modules. You can also change the library name, but it is tedious).

You cannot (unload-feature 'hello) in this case, because it is not a feature. It turns out in more complete examples that do provide a feature, you cannot unload that feature either.

John Kitchin
  • 11,555
  • 1
  • 19
  • 41
  • 1
    Could you give an example? – Dan Jul 05 '17 at 21:00
  • 1
    By dynamic module I mean this https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Modules.html. It is a compiled library (e.g. written in C). It does not appear possible to use unload-feature on them. and load appears to not update the module. I will clarify the question. – John Kitchin Jul 07 '17 at 11:24
  • ["Currently there is no way to unload a module"](https://github.com/emacs-mirror/emacs/blob/bc511a64f6da9ab51acc7c8865e80c4a4cb655c2/src/dynlib.c#L303). so even you provide a feature from `emacs_module_init`, I don't think `unload-feature` will work. If you don't want restart Emacs, you can rename the share library, e.g., `mv hello.so world.so` then `(load "world")`. – xuchunyang Oct 30 '17 at 19:57
  • 1
    Here is a related issue: [Module unloading and reloading](https://github.com/aaptel/emacs-dynamic-module/issues/36). – xuchunyang Oct 30 '17 at 20:03

2 Answers2

4

Here is a work-around:

(defun fake-module-reload (module)
  (interactive "fReload Module file: ")
  (let ((tmpfile (make-temp-file
                  (file-name-nondirectory module) nil module-file-suffix)))
    (copy-file module tmpfile t)
    (module-load tmpfile)))
xuchunyang
  • 14,302
  • 1
  • 18
  • 39
1

You can try this.

Basically it uses a bootstrap dynamic module to provide an alternative load mechanism, with support for unloading.

Although it's aimed towards Rust, it should also work with C modules that define int emacs_rs_module_init(struct emacs_runtime *ert).

;; Load the alternative loader
(module-load "/path/to/libemacs_rs_module")
;; It's important to use this instead of `module-load', `load', or `require'
(rs-module/load "/path/to/module_to_be_reloaded")

It works on Ubuntu, OS X El Capitan, Sierra. It's not working on High Sierra (potentially due to a dlclose bug).

ubolonton
  • 19
  • 2