6

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.

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)))
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).

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.