2

I am trying to write a dynamic module to expose some constants in the GNU Scientific Library. I thought something like this would do it.

#include <gsl/gsl_const_mksa.h>
#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 defconst = env->intern(env, "defconst");

  char doc[] = "Speed of light in vacuum (m/s).";
  emacs_value args[] = {
    env->intern(env, "GSL-CONST-MKSA-SPEED-OF-LIGHT"),
    env->make_float(env, GSL_CONST_MKSA_SPEED_OF_LIGHT),
    env->make_string(env, doc, sizeof doc)
    };

  env->funcall(env, defconst, 3, args);

  // This is what allows the shared library to provide a feature 
  emacs_value provide = env->intern(env, "provide");
  emacs_value provide_args[] = { env->intern(env, "gsl-constants") };
  env->funcall(env, provide, 1, provide_args);

  return 0;
}

This compiles fine with

gcc -Wall -I/usr/local/include -fPIC -c gsl-constants.c
gcc -shared -L/usr/local/include -lgsl -o gsl-constants.so gsl-constants.o

But something is not working because I get "Required feature ‘gsl-constants’ was not provided" if I try to (require 'gsl-constants).

I guess that something is wrong with the defconst part because if I comment that out, it requires fine. Does anyone know if there is another way to define constants or variables in a dynamic module?

  • My C isn't great, but are you sure that sizeof doc is what you want? Maybe you wanted the length of the string? i.e. strlen. Also, it's probably better to add a few consts when you work with literal strings. – wvxvw Jul 9 '17 at 15:05
  • I might want strlen, but it also doesn't work if I just leave the third argument out, so I don't think it is related to the string. – John Kitchin Jul 9 '17 at 15:06
1

Apparently you can not funcall special forms. At least not the ones having unevaluated arguments, with defconst beeing one of them.

(funcall 'defconst 'foo 42 "Hey")
 => Debugger entered--Lisp error: (invalid-function defconst)

So the env->funcall(...) signals an error, which goes by unnoticed since you don't inspect its return value. Also, it seems that the following calls into the module API are silently ignored in this scenario.

  • That is a good tip. It looks like there is no way to do it this way. You can (funcall 'set 'sym val) but quote is a special form too, so I can't quote it in the C code. Also emacs segfaults when I try that! Thanks for pointing this out. – John Kitchin Jul 9 '17 at 21:26
  • I think you can build a list (defconst ...) and then call eval with it. – politza Jul 9 '17 at 21:52
  • That is genius and works! for the record I will post what worked below. – John Kitchin Jul 9 '17 at 22:50
  • I don't think need quote with set, since env->funcall does not (re)evaluate the arguments. – politza Jul 10 '17 at 0:07
  • I think I tried it both ways and it segfaulted both times IIRC. – John Kitchin Jul 10 '17 at 0:12
2

Here is what I finally got to work. @politza pointed out that you cannot use funcall on special forms (eg. macros), and apply does not work either. @politza also pointed out that you can build up a list of symbols and then eval it. That is what the code below does. Thanks for the help!

#include <gsl/gsl_const_mksa.h>
#include <string.h>
#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 eval = env->intern(env, "eval");  
  emacs_value list = env->intern(env, "list");
  emacs_value defconst = env->intern(env, "defconst");

  emacs_value sym = env->intern(env, "GSL-CONST-MKSA-SPEED-OF-LIGHT");
  emacs_value val = env->make_float(env, GSL_CONST_MKSA_SPEED_OF_LIGHT);

  char doc[] = "Speed of light in vacuum (m/s).";
  emacs_value sdoc = env->make_string(env, doc, strlen(doc));

  emacs_value largs[] = {defconst, sym, val, sdoc};
  emacs_value qlist = env->funcall(env, list, 4, &largs);   
  emacs_value args[] = { qlist };

  env->funcall(env, eval, 1, &args);

  // This is what allows the shared library to provide a feature 
  emacs_value provide = env->intern(env, "provide");
  emacs_value provide_args[] = { env->intern(env, "gsl-constants") };
  env->funcall(env, provide, 1, provide_args);

  return 0;
}

Once compiled, you use it like this:

#+BEGIN_SRC emacs-lisp
(add-to-list 'load-path "/Users/jkitchin/vc/blogofile-jkitchin.github.com/_blog/dynamic-module/")
(require 'gsl-constants)
GSL-CONST-MKSA-SPEED-OF-LIGHT
#+END_SRC

#+RESULTS:
: 299792458.0

#+BEGIN_SRC emacs-lisp
(describe-variable 'GSL-CONST-MKSA-SPEED-OF-LIGHT)
#+END_SRC

#+RESULTS:
: GSL-CONST-MKSA-SPEED-OF-LIGHT’s value is 299792458.0
: 
:   This variable may be risky if used as a file-local variable.
: 
: Documentation:
: Speed of light in vacuum (m/s).

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.