2

Background

I am running Emacs version

GNU Emacs 26.0.50 (build 1, x86_64-pc-linux-gnu, X toolkit, Xaw3d scroll bars) of 2017-05-28

I am writing a toy dynamic module to interface with GNU/Linux utilities following this guide. My module compiles, loads and runs successfully, but the information reported by the help system leaves something to be desired. Is there a way to achieve the same level of integration as with built-in functions?

Module definition

My module foo.c (which compiles to foo.so) includes the following:

#define FOO_DOC "Frobnicate BAR.\n\n(fn BAR)"

static emacs_value Ffoo (/* ... args ... */) { /* ... body ... */ }

int
emacs_module_init (struct emacs_runtime *ert)
{
  emacs_value Qfset, Qprovide, Qfoo, Sfoo;
  emacs_env *env = ert->get_environment (ert);

  Qfset    = env->intern (env, "fset");
  Qprovide = env->intern (env, "provide");
  Qfoo     = env->intern (env, "foo");
  Sfoo     = env->make_function (env, 1, 1, Ffoo, FOO_DOC, NULL);

  env->funcall (env, Qfset,    2, (emacs_value[]) {Qfoo, Sfoo});
  env->funcall (env, Qprovide, 1, &Qfoo);

  return EXIT_SUCCESS;
}

Desired behaviour

Here is an example of what describe-function reports for mapc:

mapc is a built-in function in ‘src/fns.c’.

(mapc FUNCTION SEQUENCE)

Apply FUNCTION to each element of SEQUENCE for side effects only.
Unlike ‘mapcar’, don’t accumulate the results.  Return SEQUENCE.
SEQUENCE may be a list, a vector, a bool-vector, or a string.

where the quoted filename src/fns.c forms a link to the function's definition.

Actual behaviour

When the module function foo is defined using fset, as per the source listing above and the linked blog post, describe-function reports the following:

foo is .

(foo BAR)

Frobnicate BAR.

Furthermore, inspecting load-history reveals the following:

("/path/to/baz.el"
 (require . foo)
 (provide . foo)
 ;; ... other baz.el definitions ...
 (provide . baz))

where baz.el calls (require 'foo) and which itself gets loaded as part of my startup.


If I replace fset with defalias in the module, I instead get:

foo is in ‘baz.el’.

(foo BAR)

Frobnicate BAR.

and load-history includes an additional defun:

("/path/to/baz.el"
 (require . foo)
 (defun   . foo)
 (provide . foo)
 ;; ... other baz.el definitions ...
 (provide . baz))

Questions

  1. How can I tell Emacs that the function foo is a function and defined in the dynamic module foo.c, not the elisp file which loaded it, baz.el?
  2. Does the help system support links to module sources?
  3. Is there a better way to export module functions than the described defalias approach?
  4. Is there a better way to load a module than (require 'module-feature)?
1

How can I tell Emacs that the function foo is a function and defined in the dynamic module foo.c, not the elisp file which loaded it, baz.el?

Emacs 27 now knows this. Well, technically it knows that foo is a function defined in foo.so, but you can then translate this to foo.c pretty easily, e.g.:

(replace-regexp-in-string (rx (eval module-file-suffix) eos)
                          ".c" (symbol-file 'foo))
  ;; ⇒ "/path/to/foo.c"

Does the help system support links to module sources?

To an extent. It now reports:

foo is a module function in `foo.so'.

(foo BAR)

Frobnicate BAR.

where foo.so is linked to the .so file, not the location where foo is defined in foo.c, as is usually the case for built-in subroutines. Better support may be added in the future.

Is there a better way to export module functions than the described defalias approach?

No.

Is there a better way to load a module than (require 'module-feature)?

No.

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.