Commit 3f3ff599 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Change the specification format in the compiled VMOD from our own

home-rolled stuff to VJSN in anticipation of more complex
specifications in the future.
parent f96fcf06
......@@ -128,7 +128,7 @@ VRT_Vmod_Init(VRT_CTX, struct vmod **hdl, void *ptr, int len, const char *nm,
d->func == NULL ||
d->func_len <= 0 ||
d->proto == NULL ||
d->spec == NULL) {
d->json == NULL) {
VSB_printf(ctx->msg,
"Loading VMOD %s from %s:\n", nm, path);
VSB_printf(ctx->msg, "VMOD data is mangled.\n");
......
......@@ -209,7 +209,7 @@ struct vmod_data {
const void *func;
int func_len;
const char *proto;
const char * const *spec;
const char *json;
const char *abi;
};
......
......@@ -71,6 +71,7 @@ struct acl_e;
struct proc;
struct expr;
struct vcc;
struct vjsn_val;
struct symbol;
struct source {
......@@ -308,8 +309,8 @@ void vcc_Expr_Init(struct vcc *tl);
sym_expr_t vcc_Eval_Var;
sym_expr_t vcc_Eval_Handle;
sym_expr_t vcc_Eval_SymFunc;
void vcc_Eval_Func(struct vcc *tl, const char *spec,
const char *extra, const struct symbol *sym);
void vcc_Eval_Func(struct vcc *, const struct vjsn_val *,
const char *, const struct symbol *);
void VCC_GlobalSymbol(struct symbol *, vcc_type_t fmt, const char *pfx);
struct symbol *VCC_HandleSymbol(struct vcc *, vcc_type_t , const char *);
......
......@@ -36,6 +36,7 @@
#include <string.h>
#include "vcc_compile.h"
#include "vjsn.h"
struct expr {
unsigned magic;
......@@ -400,7 +401,7 @@ vcc_priv_arg(struct vcc *tl, const char *p, const char *name, const char *vmod)
struct func_arg {
vcc_type_t type;
const char *enum_bits;
const struct vjsn_val *enums;
const char *cname;
const char *name;
const char *val;
......@@ -423,25 +424,20 @@ vcc_do_enum(struct vcc *tl, struct func_arg *fa, int len, const char *ptr)
static void
vcc_do_arg(struct vcc *tl, struct func_arg *fa)
{
const char *p, *r;
struct expr *e2;
struct vjsn_val *vv;
if (fa->type == ENUM) {
ExpectErr(tl, ID);
ERRCHK(tl);
r = p = fa->enum_bits;
do {
if (vcc_IdIs(tl->t, p))
VTAILQ_FOREACH(vv, &fa->enums->children, list)
if (vcc_IdIs(tl->t, vv->value))
break;
p += strlen(p) + 1;
} while (*p != '\1');
if (*p == '\1') {
if (vv == NULL) {
VSB_printf(tl->sb, "Wrong enum value.");
VSB_printf(tl->sb, " Expected one of:\n");
do {
VSB_printf(tl->sb, "\t%s\n", r);
r += strlen(r) + 1;
} while (*r != '\0' && *r != '\1');
VTAILQ_FOREACH(vv, &fa->enums->children, list)
VSB_printf(tl->sb, "\t%s\n", vv->value);
vcc_ErrWhere(tl, tl->t);
return;
}
......@@ -456,60 +452,59 @@ vcc_do_arg(struct vcc *tl, struct func_arg *fa)
}
static void
vcc_func(struct vcc *tl, struct expr **e, const char *spec,
vcc_func(struct vcc *tl, struct expr **e, const void *priv,
const char *extra, const struct symbol *sym)
{
vcc_type_t rfmt;
const char *args;
const char *cfunc;
const char *p;
struct expr *e1;
struct func_arg *fa, *fa2;
VTAILQ_HEAD(,func_arg) head;
struct token *t1;
const struct vjsn_val *vv, *vvp;
rfmt = VCC_Type(spec);
spec += strlen(spec) + 1;
cfunc = spec;
spec += strlen(spec) + 1;
args = spec;
CAST_OBJ_NOTNULL(vv, priv, VJSN_VAL_MAGIC);
assert(vv->type == VJSN_ARRAY);
vv = VTAILQ_FIRST(&vv->children);
rfmt = VCC_Type(VTAILQ_FIRST(&vv->children)->value);
AN(rfmt);
vv = VTAILQ_NEXT(vv, list);
cfunc = vv->value;
vv = VTAILQ_NEXT(vv, list);
SkipToken(tl, '(');
p = args;
if (extra == NULL)
extra = "";
AN(rfmt);
VTAILQ_INIT(&head);
while (*p != '\0') {
for(;vv != NULL; vv = VTAILQ_NEXT(vv, list)) {
assert(vv->type == VJSN_ARRAY);
fa = calloc(1, sizeof *fa);
AN(fa);
fa->cname = cfunc;
VTAILQ_INSERT_TAIL(&head, fa, list);
if (!memcmp(p, "PRIV_", 5)) {
fa->result = vcc_priv_arg(tl, p, sym->name, sym->vmod);
vvp = VTAILQ_FIRST(&vv->children);
if (!memcmp(vvp->value, "PRIV_", 5)) {
fa->result = vcc_priv_arg(tl, vvp->value,
sym->name, sym->vmod);
fa->name = "";
p += strlen(p) + 1;
continue;
}
fa->type = VCC_Type(p);
fa->type = VCC_Type(vvp->value);
AN(fa->type);
p += strlen(p) + 1;
if (*p == '\1') {
fa->enum_bits = ++p;
while (*p != '\1')
p += strlen(p) + 1;
p++;
assert(*p == '\0');
p++;
}
if (*p == '\2') {
fa->name = p + 1;
p += strlen(p) + 1;
}
if (*p == '\3') {
fa->val = p + 1;
p += strlen(p) + 1;
vvp = VTAILQ_NEXT(vvp, list);
if (vvp != NULL) {
fa->name = vvp->value;
vvp = VTAILQ_NEXT(vvp, list);
if (vvp != NULL) {
fa->val = vvp->value;
vvp = VTAILQ_NEXT(vvp, list);
if (vvp != NULL) {
fa->enums = vvp;
vvp = VTAILQ_NEXT(vvp, list);
}
}
}
assert(*p == 0 || *p > ' ');
AZ(vvp);
}
VTAILQ_FOREACH(fa, &head, list) {
......@@ -576,11 +571,12 @@ vcc_func(struct vcc *tl, struct expr **e, const char *spec,
SkipToken(tl, ')');
}
/*--------------------------------------------------------------------
*/
void
vcc_Eval_Func(struct vcc *tl, const char *spec,
vcc_Eval_Func(struct vcc *tl, const struct vjsn_val *spec,
const char *extra, const struct symbol *sym)
{
struct expr *e = NULL;
......@@ -605,7 +601,6 @@ vcc_Eval_SymFunc(struct vcc *tl, struct expr **e, struct token *t,
assert(sym->kind == SYM_FUNC);
AN(sym->eval_priv);
// assert(sym->fmt == VCC_Type(sym->eval_priv));
vcc_func(tl, e, sym->eval_priv, sym->extra, sym);
ERRCHK(tl);
if ((*e)->fmt == STRING) {
......@@ -1261,7 +1256,7 @@ vcc_Act_Call(struct vcc *tl, struct token *t, struct symbol *sym)
struct expr *e;
e = NULL;
vcc_Eval_SymFunc(tl, &e, t, sym, VOID);
vcc_func(tl, &e, sym->eval_priv, sym->extra, sym);
if (!tl->err) {
vcc_expr_fmt(tl->fb, tl->indent, e);
SkipToken(tl, ';');
......
......@@ -36,6 +36,7 @@
#include "libvcc.h"
#include "vfil.h"
#include "vjsn.h"
#include "vmod_abi.h"
static int
......@@ -54,18 +55,97 @@ vcc_path_dlopen(void *priv, const char *fn)
return (0);
}
static void
func_sym(struct symbol *sym, const char *vmod, const struct vjsn_val *v)
{
assert(v->type == VJSN_ARRAY);
sym->action = vcc_Act_Call;
sym->vmod = vmod;
sym->eval = vcc_Eval_SymFunc;
sym->eval_priv = v;
v = VTAILQ_FIRST(&v->children);
assert(v->type == VJSN_ARRAY);
v = VTAILQ_FIRST(&v->children);
assert(v->type == VJSN_STRING);
sym->type = VCC_Type(v->value);
AN(sym->type);
}
static void
parse_json(struct vcc * tl, const char *vmod, const char *json)
{
struct inifin *ifp;
struct vjsn *vj;
struct vjsn_val *vv, *vv2;
double vmod_syntax = 0.0;
const char *p;
struct symbol *sym;
ifp = NULL;
vj = vjsn_parse(json, &p);
XXXAZ(p);
AN(vj);
VTAILQ_FOREACH(vv, &vj->value->children, list) {
assert(vv->type == VJSN_ARRAY);
vv2 = VTAILQ_FIRST(&vv->children);
assert(vv2->type == VJSN_STRING);
if (!strcmp(vv2->value, "$VMOD")) {
vmod_syntax =
strtod(VTAILQ_NEXT(vv2, list)->value, NULL);
continue;
}
assert (vmod_syntax == 1.0);
if (!strcmp(vv2->value, "$EVENT")) {
/* XXX: What about the rest of the events ? */
if (ifp == NULL)
ifp = New_IniFin(tl);
vv2 = VTAILQ_NEXT(vv2, list);
VSB_printf(ifp->ini,
"\tif (%s(ctx, &vmod_priv_%s, VCL_EVENT_LOAD))\n"
"\t\treturn(1);",
vv2->value, vmod);
VSB_printf(ifp->fin,
"\t\t(void)%s(ctx, &vmod_priv_%s,\n"
"\t\t\t VCL_EVENT_DISCARD);\n",
vv2->value, vmod);
VSB_printf(ifp->event, "%s(ctx, &vmod_priv_%s, ev)",
vv2->value, vmod);
} else if (!strcmp(vv2->value, "$FUNC")) {
vv2 = VTAILQ_NEXT(vv2, list);
sym = VCC_MkSym(tl,
vv2->value, SYM_FUNC, VCL_LOW, VCL_HIGH);
ERRCHK(tl);
AN(sym);
func_sym(sym, vmod, VTAILQ_NEXT(vv2, list));
} else if (!strcmp(vv2->value, "$OBJ")) {
vv2 = VTAILQ_NEXT(vv2, list);
sym = VCC_MkSym(tl, vv2->value,
SYM_OBJECT, VCL_LOW, VCL_HIGH);
XXXAN(sym);
sym->eval_priv = vv2;
sym->vmod = vmod;
} else {
VTAILQ_FOREACH(vv2, &vv->children, list)
fprintf(stderr, "\tt %s n %s v %s\n",
vv2->type, vv2->name, vv2->value);
WRONG("Vmod JSON syntax error");
}
}
}
void
vcc_ParseImport(struct vcc *tl)
{
void *hdl;
char fn[1024], *fnp, *fnpx;
char buf[256];
const char *p;
struct token *mod, *t1;
struct inifin *ifp;
const char * const *spec;
struct symbol *sym;
struct symbol *msym;
const char *p;
const struct vmod_data *vmd;
t1 = tl->t;
......@@ -216,48 +296,7 @@ vcc_ParseImport(struct vcc *tl)
VSB_printf(ifp->fin, "\t\tVRT_priv_fini(&vmod_priv_%.*s);\n", PF(mod));
VSB_printf(ifp->fin, "\t\t\tVRT_Vmod_Fini(&VGC_vmod_%.*s);", PF(mod));
ifp = NULL;
spec = vmd->spec;
for (; *spec != NULL; spec++) {
p = *spec;
if (!strcmp(p, "$OBJ")) {
p += strlen(p) + 1;
sym = VCC_MkSym(tl, p, SYM_OBJECT, VCL_LOW, VCL_HIGH);
XXXAN(sym);
sym->extra = p;
sym->vmod = msym->name;
} else if (!strcmp(p, "$EVENT")) {
p += strlen(p) + 1;
if (ifp == NULL)
ifp = New_IniFin(tl);
VSB_printf(ifp->ini,
"\tif (%s(ctx, &vmod_priv_%.*s, VCL_EVENT_LOAD))\n"
"\t\treturn(1);",
p, PF(mod));
VSB_printf(ifp->fin,
"\t\t(void)%s(ctx, &vmod_priv_%.*s,\n"
"\t\t\t VCL_EVENT_DISCARD);\n", p, PF(mod));
VSB_printf(ifp->event, "%s(ctx, &vmod_priv_%.*s, ev)",
p, PF(mod));
} else if (!strcmp(p, "$FUNC")) {
p += strlen(p) + 1;
sym = VCC_MkSym(tl, p, SYM_FUNC, VCL_LOW, VCL_HIGH);
ERRCHK(tl);
AN(sym);
sym->action = vcc_Act_Call;
sym->vmod = msym->name;
sym->eval = vcc_Eval_SymFunc;
p += strlen(p) + 1;
sym->eval_priv = p;
sym->type = VCC_Type(p);
AN(sym->type);
} else {
VSB_printf(tl->sb, "Internal spec error (%s)\n", p);
vcc_ErrWhere(tl, mod);
return;
}
}
parse_json(tl, msym->name, vmd->json);
Fh(tl, 0, "\n/* --- BEGIN VMOD %.*s --- */\n\n", PF(mod));
Fh(tl, 0, "static struct vmod *VGC_vmod_%.*s;\n", PF(mod));
......@@ -271,9 +310,11 @@ vcc_Act_New(struct vcc *tl, struct token *t, struct symbol *sym)
{
struct symbol *sy1, *sy2, *sy3;
struct inifin *ifp;
const char *p, *s_obj;
const char *s_obj;
char buf1[128];
char buf2[128];
const struct vjsn_val *vv, *vf;
const char *p;
(void)sym;
ExpectErr(tl, ID);
......@@ -292,7 +333,7 @@ vcc_Act_New(struct vcc *tl, struct token *t, struct symbol *sym)
sy2 = VCC_SymbolGet(tl, SYM_OBJECT, "Symbol not found", XREF_NONE);
ERRCHK(tl);
AN(sy2);
if (sy2->extra == NULL) {
if (sy2->eval_priv == NULL) {
VSB_printf(tl->sb, "Constructor not found: ");
vcc_ErrToken(tl, t);
VSB_printf(tl->sb, " at ");
......@@ -300,49 +341,53 @@ vcc_Act_New(struct vcc *tl, struct token *t, struct symbol *sym)
return;
}
p = sy2->extra;
AN(p);
CAST_OBJ_NOTNULL(vv, sy2->eval_priv, VJSN_VAL_MAGIC);
s_obj = vv->value;
vv = VTAILQ_NEXT(vv, list);
Fh(tl, 0, "static %s *%s;\n\n", vv->value, sy1->rname);
vv = VTAILQ_NEXT(vv, list);
s_obj = p;
p += strlen(p) + 1;
vf = VTAILQ_FIRST(&vv->children);
vv = VTAILQ_NEXT(vv, list);
assert(vf->type == VJSN_STRING);
assert(!strcmp(vf->value, "$INIT"));
Fh(tl, 0, "static %s *%s;\n\n", p, sy1->rname);
p += strlen(p) + 1;
vf = VTAILQ_NEXT(vf, list);
bprintf(buf1, ", &%s, \"%s\"", sy1->rname, sy1->name);
vcc_Eval_Func(tl, p, buf1, sy2);
vcc_Eval_Func(tl, vf, buf1, sy2);
ERRCHK(tl);
SkipToken(tl, ';');
sy1->def_e = tl->t;
while (p[0] != '\0' || p[1] != '\0' || p[2] != '\0')
p++;
p += 3;
vf = VTAILQ_FIRST(&vv->children);
vv = VTAILQ_NEXT(vv, list);
assert(vf->type == VJSN_STRING);
assert(!strcmp(vf->value, "$FINI"));
vf = VTAILQ_NEXT(vf, list);
vf = VTAILQ_FIRST(&vf->children);
vf = VTAILQ_NEXT(vf, list);
ifp = New_IniFin(tl);
p += strlen(p) + 1;
VSB_printf(ifp->fin, "\t\t%s(&%s);", p, sy1->rname);
while (p[0] != '\0' || p[1] != '\0' || p[2] != '\0')
p++;
p += 3;
VSB_printf(ifp->fin, "\t\t%s(&%s);", vf->value, sy1->rname);
/* Instantiate symbols for the methods */
bprintf(buf1, ", %s", sy1->rname);
while (*p != '\0') {
p += strlen(s_obj);
bprintf(buf2, "%s%s", sy1->name, p);
p = TlDup(tl, buf1);
while (vv != NULL) {
vf = VTAILQ_FIRST(&vv->children);
assert(vf->type == VJSN_STRING);
assert(!strcmp(vf->value, "$METHOD"));
vf = VTAILQ_NEXT(vf, list);
assert(vf->type == VJSN_STRING);
bprintf(buf2, "%s%s", sy1->name, vf->value + strlen(s_obj));
sy3 = VCC_MkSym(tl, buf2, SYM_FUNC, VCL_LOW, VCL_HIGH);
AN(sy3);
sy3->action = vcc_Act_Call;
sy3->eval = vcc_Eval_SymFunc;
p += strlen(p) + 1;
sy3->eval_priv = p;
sy3->type = VCC_Type(p);
sy3->extra = TlDup(tl, buf1);
sy3->vmod = sy2->vmod;
while (p[0] != '\0' || p[1] != '\0' || p[2] != '\0')
p++;
p += 3;
func_sym(sy3, sy2->vmod, VTAILQ_NEXT(vf, list));
sy3->extra = p;
vv = VTAILQ_NEXT(vv, list);
}
sy1->def_e = tl->t;
}
......@@ -43,6 +43,7 @@ import optparse
import unittest
import random
import copy
import json
rstfmt = False
strict_abi = True
......@@ -227,24 +228,10 @@ class ctype(object):
return self.vt
return self.vt + " {" + ",".join(self.spec) + "}"
def specstr(self, fo, p):
fo.write(p + '"' + self.vt)
fo.write('\\0"\n')
p = indent(p, 4)
if self.spec is not None:
fo.write(p + '"\\1"\n')
p = indent(p, 4)
for i in self.spec:
fo.write(p + '"' + i + '\\0"\n')
p = indent(p, -4)
# This terminating \1 is necessary to ensure that
# a prototype always ends with three \0's
fo.write(p + '"\\1\\0"\n')
if self.nm is not None:
fo.write(p + '"\\2" "' + self.nm + '\\0"\n')
if self.defval is not None:
fo.write(p + '"\\3" "' + quote(self.defval) + '\\0"\n')
def json(self, jl):
jl.append([self.vt, self.nm, self.defval, self.spec])
while jl[-1][-1] is None:
jl[-1].pop(-1)
def vtype(txt):
j = len(txt)
......@@ -404,17 +391,13 @@ class prototype(object):
s += '%s %s(%s);' % (self.c_ret(), fn, self.c_args(args))
return "\n".join(lwrap(s)) + "\n"
def specstr(self, fo, cfunc, p):
if self.retval is None:
fo.write(p + '"VOID\\0"\n')
else:
self.retval.specstr(fo, p)
fo.write(p + '"' + cfunc + '\\0"\n')
p = indent(p, 4)
if self.args is not None:
for i in self.args:
i.specstr(fo, p)
fo.write(p + '"\\0"\n')
def json(self, jl, cfunc):
ll = []
self.retval.json(ll)
ll.append(cfunc)
for i in self.args:
i.json(ll)
jl.append(ll)
#######################################################################
......@@ -469,7 +452,7 @@ class stanza(object):
def cstruct_init(self, fo):
return
def specstr(self, fo):
def json(self, jl):
return
#######################################################################
......@@ -568,10 +551,11 @@ class s_event(stanza):
def cstruct_init(self, fo):
fo.write("\t%s,\n" % self.event_func)
def specstr(self, fo):
fo.write('\t"$EVENT\\0"\n\t "Vmod_%s_Func._event",\n\n' %
self.vcc.modname)
def json(self, jl):
jl.append([
"$EVENT",
"Vmod_%s_Func._event" % self.vcc.modname
])
class s_function(stanza):
def parse(self):
......@@ -591,12 +575,13 @@ class s_function(stanza):
def cstruct_init(self, fo):
fo.write("\t" + self.proto.cname(pfx=True) + ",\n")
def specstr(self, fo):
fo.write('\t"$FUNC\\0"\t"%s.%s\\0"\n\n' %
(self.vcc.modname, self.proto.name))
self.proto.specstr(fo, 'Vmod_%s_Func.%s' %
(self.vcc.modname, self.proto.cname()), "\t ")
fo.write('\t "\\0",\n\n')
def json(self,jl):
jl.append([
"$FUNC",
"%s.%s" % (self.vcc.modname, self.proto.name),
])
self.proto.json(jl[-1], 'Vmod_%s_Func.%s' %
(self.vcc.modname, self.proto.cname()))
class s_object(stanza):
......@@ -663,29 +648,29 @@ class s_object(stanza):
i.cstruct_init(fo)
fo.write("\n")
def specstr(self, fo):
def json(self, jl):
ll = [
"$OBJ",
self.vcc.modname + "." + self.proto.name,
"struct %s%s_%s" %
(self.vcc.sympfx, self.vcc.modname, self.proto.name),
]
fo.write('\t"$OBJ\\0"\t"%s.%s\\0"\n\n' %
(self.vcc.modname, self.proto.name))
l2 = [ "$INIT" ]
ll.append(l2)
self.init.json(l2,
'Vmod_%s_Func.%s' % (self.vcc.modname, self.init.name))
fo.write('\t "struct %s%s_%s\\0"\n' %
(self.vcc.sympfx, self.vcc.modname, self.proto.name))
fo.write("\n")
self.proto.specstr(fo, 'Vmod_%s_Func.%s' %
(self.vcc.modname, self.init.name), '\t ')
fo.write('\t "\\0"\n\n')
fo.write('\t "VOID\\0"\n')
fo.write('\t "Vmod_%s_Func.%s\\0"\n' %
(self.vcc.modname, self.fini.name))
fo.write('\t\t"\\0"\n')
fo.write('\t "\\0"\n\n')
l2 = [ "$FINI" ]
ll.append(l2)
self.fini.json(l2,
'Vmod_%s_Func.%s' % (self.vcc.modname, self.fini.name))
for i in self.methods:
i.specstr(fo)
i.json(ll)
jl.append(ll)
fo.write('\t "\\0",\n\n')
def dump(self):
super(s_object, self).dump()
......@@ -707,12 +692,14 @@ class s_method(stanza):
def cstruct_init(self, fo):
fo.write('\t' + self.proto.cname(pfx=True) + ",\n")
def specstr(self, fo):
fo.write('\t "%s.%s\\0"\n' %
(self.vcc.modname, self.proto.name))
self.proto.specstr(fo, 'Vmod_%s_Func.%s' %
(self.vcc.modname, self.proto.cname()), '\t\t')
fo.write('\t\t"\\0"\n\n')
def json(self, jl):
jl.append([
"$METHOD",
self.vcc.modname + "." + self.proto.name
])
self.proto.json(jl[-1],
'Vmod_%s_Func.%s' % (self.vcc.modname, self.proto.cname()))
#######################################################################
......@@ -836,15 +823,29 @@ class vcc(object):
fo.write("\t&%senum_%s,\n" % (self.sympfx, j))
fo.write("};\n")
def specstr(self, fo):
fo.write("\n/*lint -save -e786 -e840 */\n")
fo.write("static const char * const Vmod_Spec[] = {\n")
def json(self, fo):
jl = [ ["$VMOD", "1.0" ] ]
for j in self.contents:
j.specstr(fo)
fo.write("\t0\n")
fo.write("};\n")
fo.write("/*lint -restore */\n")
j.json(jl)
bz = bytearray(json.dumps(jl, separators=(",",":"))) + "\0"
fo.write("\nstatic const char Vmod_Json[%d] = {\n" % len(bz))
t = "\t"
for i in bz:
t += "%d," % i
if len(t) >= 69:
fo.write(t + "\n")
t = "\t"
if len(t) > 1:
fo.write(t[:-1])
fo.write("\n};\n\n")
for i in json.dumps(jl, indent=2, separators=(',', ': ')).split("\n"):
j = "// " + i
if len(j) > 72:
fo.write(j[:72] + "[...]\n")
else:
fo.write(j + "\n")
fo.write("\n")
def api(self, fo):
for i in (714, 759, 765):
......@@ -863,7 +864,7 @@ class vcc(object):
fo.write('\t.func =\t\t&Vmod_Func,\n')
fo.write('\t.func_len =\tsizeof(Vmod_Func),\n')
fo.write('\t.proto =\tVmod_Proto,\n')
fo.write('\t.spec =\t\tVmod_Spec,\n')
fo.write('\t.json =\t\tVmod_Json,\n')
fo.write('\t.abi =\t\tVMOD_ABI_Version,\n')
# NB: Sort of hackish:
# Fill file_id with random stuff, so we can tell if
......@@ -927,7 +928,7 @@ class vcc(object):
os.remove(fn2)
self.specstr(fo)
self.json(fo)
self.api(fo)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment