3 # Module helper script.
5 # Copyright 2015-2018 Free Software Foundation, Inc.
7 # This file is part of GNU Emacs.
9 # GNU Emacs is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
14 # GNU Emacs is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
24 import subprocess
as sp
28 EMACS
= os
.path
.join('..', 'src', 'emacs')
32 for (dirname
, dirs
, files
) in os
.walk('.'):
33 if 'Makefile' in files
:
34 modpaths
.append(dirname
)
48 print('[*] %s: ------- start -------' % m
)
49 print('[*] %s: running make' % m
)
50 r
= sp
.call(make_cmd
, cwd
=m
)
52 print('[E] %s: make failed' % m
)
56 print('[*] %s: running test' % m
)
57 testpath
= os
.path
.join(m
, 'test.el')
58 if os
.path
.isfile(testpath
):
59 emacs_cmd
= [EMACS
, '-batch', '-L', '.', '-l', 'ert',
60 '-l', testpath
, '-f', 'ert-run-tests-batch-and-exit']
61 print(' '.join(emacs_cmd
))
62 r
= sp
.call(emacs_cmd
)
64 print('[E] %s: test failed' % m
)
68 print('[W] %s: no test to run' % m
)
70 print('\n[*] %d/%d MODULES OK' % (len(mods
)-len(failed
), len(mods
)))
72 print('\tfailed: %s' % m
)
75 sym
= re
.sub('[_ ]', '-', sym
)
79 sym
= re
.sub('[- ]', '_', sym
)
83 if os
.path
.exists(args
.module
):
84 print("%s: file/dir '%s' already exists" % (__file__
, args
.module
))
90 'module': args
.module
,
92 'c_file': '%s.c' % args
.module
,
93 'c_func': 'F%s_%s' % (to_c_sym(args
.module
), to_c_sym(args
.fun
)),
94 'lisp_func': '%s-%s' % (args
.module
, to_lisp_sym(args
.fun
)),
97 for path
, t
in TEMPLATES
.items():
98 if isinstance(path
, string
.Template
):
99 path
= path
.substitute(template_vars
)
100 path
= os
.path
.join(args
.module
, path
)
101 print("writing %s..." % path
)
102 with
open(path
, "w+") as f
:
103 f
.write(t
.substitute(template_vars
))
104 print("done! you can run %s test %s" % (__file__
, args
.module
))
108 # path always written relative to this file
109 os
.chdir(os
.path
.dirname(os
.path
.realpath(__file__
)))
111 mainp
= argparse
.ArgumentParser()
112 subp
= mainp
.add_subparsers()
114 testp
= subp
.add_parser('test', help='run tests')
115 testp
.add_argument('-f', '--force', action
='store_true',
116 help='force regeneration (make -B)')
117 testp
.add_argument('module', nargs
='*',
118 help='path to module to test (default all)')
119 testp
.set_defaults(func
=cmd_test
)
121 initp
= subp
.add_parser('init', help='create a test module from a template')
122 initp
.add_argument('module', help='name of the new module')
123 initp
.add_argument('-f', '--fun', default
='fun',
124 help='override name of the default function')
125 initp
.set_defaults(func
=cmd_init
)
127 args
= mainp
.parse_args()
131 # double the $ to escape python template syntax
133 'Makefile': string
.Template('''
138 CFLAGS = -ggdb3 -Wall
141 all: ${module}.so ${module}.doc
144 $$(LD) -shared $$(LDFLAGS) -o $$@ $$<
147 $$(CC) $$(CFLAGS) -I$$(ROOT)/src -fPIC -c $$<
151 string
.Template('${c_file}'): string
.Template('''
152 #include <emacs-module.h>
154 int plugin_is_GPL_compatible;
157 ${c_func} (emacs_env *env, ptrdiff_t nargs, emacs_value args[], void *data)
159 return env->intern (env, "t");
162 /* Bind NAME to FUN. */
164 bind_function (emacs_env *env, const char *name, emacs_value Sfun)
166 emacs_value Qfset = env->intern (env, "fset");
167 emacs_value Qsym = env->intern (env, name);
168 emacs_value args[] = { Qsym, Sfun };
170 env->funcall (env, Qfset, 2, args);
173 /* Provide FEATURE to Emacs. */
175 provide (emacs_env *env, const char *feature)
177 emacs_value Qfeat = env->intern (env, feature);
178 emacs_value Qprovide = env->intern (env, "provide");
179 emacs_value args[] = { Qfeat };
181 env->funcall (env, Qprovide, 1, args);
185 emacs_module_init (struct emacs_runtime *ert)
187 emacs_env *env = ert->get_environment (ert);
188 bind_function (env, "${lisp_func}",
189 env->make_function (env, 1, 1, ${c_func}, "doc", NULL));
190 provide (env, "${module}");
194 'test.el': string
.Template('''
196 (require 'module-test-common)
198 ;; #$$ works when loading, buffer-file-name when evaluating from emacs
199 (module-load (module-path (or #$$ (expand-file-name (buffer-file-name)))))
201 (ert-deftest ${lisp_func}-test ()
202 (should (eq (${lisp_func} 42) t)))
206 if __name__
== '__main__':