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?

John Kitchin
  • 11,555
  • 1
  • 19
  • 41
  • 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 `const`s when you work with literal strings. – wvxvw Jul 09 '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 09 '17 at 15:06

2 Answers2

4

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).
John Kitchin
  • 11,555
  • 1
  • 19
  • 41
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.

politza
  • 3,316
  • 14
  • 16