
32 changed files with 347 additions and 271 deletions
@ -0,0 +1,26 @@ |
|||||
|
pEpACIDgen |
||||
|
========== |
||||
|
|
||||
|
pEpACIDgen stands for "pEp Abstract C Interface Description Generator" |
||||
|
|
||||
|
pEpACIDgen generates an Abstract C Interface Defintion file (json or yml2) given the inputs: |
||||
|
* headerfile |
||||
|
* list of function names needed |
||||
|
* list of var names needed |
||||
|
|
||||
|
The generator searches each function/var in the headerfile (recursively) and collects all the |
||||
|
types needed (var type, return type, parm types). |
||||
|
As structs can contain further types, these dependent types need to be collected |
||||
|
recursively. |
||||
|
Finally, all the collected types will be resolved to their final underlying type. |
||||
|
If a type is primitive, nothing needs to be done, cause its already defined. |
||||
|
But types of typekind struct or enum need to be defined. |
||||
|
Their definition will be searched for in the headerfile and included in the interface definition |
||||
|
The ACID file (yml2) contains all the information needed to represent: |
||||
|
* functions |
||||
|
* vars |
||||
|
* structs |
||||
|
* enums |
||||
|
|
||||
|
well enough so they can be expressed in pyBind11. |
||||
|
use "pyBind11-CID" to generate the pyBind11 code out of the ACID file. |
@ -1,10 +0,0 @@ |
|||||
.PHONY: all clean |
|
||||
|
|
||||
all: |
|
||||
$(MAKE) -C synth_shed |
|
||||
$(MAKE) -C test_cid |
|
||||
|
|
||||
clean: |
|
||||
$(MAKE) -C synth_shed clean |
|
||||
$(MAKE) -C test_cid clean |
|
||||
|
|
@ -0,0 +1,161 @@ |
|||||
|
pEpACIDgen test library |
||||
|
----------------------- |
||||
|
This here is the test library for pEpACIDgen. |
||||
|
The C language is broken down into its components and common pattern. |
||||
|
It is a humble attempt to cover all possible combinations that can be created in the |
||||
|
C language. (like, struct containing` primitive, struct containing struct, typedef chains, |
||||
|
etc..). |
||||
|
Please note, that pointer types have not been addressed yet (at all) |
||||
|
|
||||
|
|
||||
|
The intended use of this test lib is: If you encounter a scenario using pEpACIDgen that poses problem |
||||
|
it is most likely that the scenario can be reproduced using this test lib pretty easily. |
||||
|
lets say you pEpACIDgen a function with sig: |
||||
|
|
||||
|
TT_E(*)(ACCS), where: |
||||
|
TT_E = typedef of typedef of an enum without an alias. |
||||
|
ACCS = Alias to a complex struct containing another complex struct |
||||
|
|
||||
|
These types exist already along with a systematic permutation of possible types that amount |
||||
|
to over 100 of types. |
||||
|
just write your func/var using these types and debug the generation. |
||||
|
|
||||
|
|
||||
|
The ACID format deals with items. Everything is an item. |
||||
|
There are qualifiers that can be used and combined to define an item. (list below) |
||||
|
e.g PS = primitive struct that possibly has a typedef |
||||
|
|
||||
|
Of all the possible combinations, not all are valid (C lang). Its a futile attempt |
||||
|
trying to cover all the valid ones. But an effort has been made to cover the most |
||||
|
of the valid combinations. |
||||
|
Combination of structs, enums and typedefs are systematically explored in the files: |
||||
|
* structs.h |
||||
|
* enums.h |
||||
|
* typedefs.h |
||||
|
|
||||
|
|
||||
|
For all the types defined the file: |
||||
|
* vars.h |
||||
|
|
||||
|
contains an instance of each. |
||||
|
|
||||
|
for all the possible function signature, well with a 100 types, |
||||
|
we can create 10000 different sigantures using 1 ret and 1 arg. |
||||
|
Therefore, no functions have been defined. |
||||
|
define them when you are interested in the combination, and pEpACIDgen the defintion. |
||||
|
|
||||
|
|
||||
|
Item Qualifier |
||||
|
=============== |
||||
|
V = Void already defined |
||||
|
P = Primitive Type already defined |
||||
|
S = Struct -> struct.h |
||||
|
E = Enum -> enums.h |
||||
|
A = Alias -> structs.h/enums.h |
||||
|
N = Nested (Structs only, cant be aliased) -> structs.h |
||||
|
H = Hosting (Structs only -> structs.h |
||||
|
containing the nested struct, cant be primitive) |
||||
|
T = typedef -> typedefs.h |
||||
|
I = Incomplete / (forward decl) -> struct.h/enums.h |
||||
|
|
||||
|
func_ = function -> functions.h |
||||
|
var_ = variable -> vars.h |
||||
|
|
||||
|
prefixed underline (e.g _E) means no typedef/alias exists for this item (enum in this case) |
||||
|
|
||||
|
Alias vs. Typedef |
||||
|
----------------- |
||||
|
aliased means typedef'd directly, like: |
||||
|
|
||||
|
typedef struct _X { |
||||
|
int x; |
||||
|
} X; |
||||
|
|
||||
|
(structs and enums only) |
||||
|
|
||||
|
|
||||
|
Typedef means, not typedef'd directly, but anywhere, like |
||||
|
|
||||
|
typedef _X X; |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
Structs |
||||
|
======= |
||||
|
For structs, a combination is needed to define the type of struct |
||||
|
IS = Struct (Empty or incomplete, neither primitive nor complex) |
||||
|
PS = Primitive struct (struct containing only primitive types) |
||||
|
CS = Complex struct (struct containing other structs and primitive) |
||||
|
NPS = Nested primitive struct |
||||
|
|
||||
|
Covered combinations |
||||
|
==================== |
||||
|
_IS = incomplete struct without a typedef (forward decl) |
||||
|
IS = incomplete struct |
||||
|
AIS = alias of an incomplete struct |
||||
|
(aliased) struct [ primitive | complex ] |
||||
|
---------------------------------------- |
||||
|
_PS = primitive struct without a an alias |
||||
|
PS = primitive struct |
||||
|
APS = Alias of primitive struct |
||||
|
_CS = complex struct without a an alias |
||||
|
CS = complex struct |
||||
|
ACS = alias of a complex struct |
||||
|
_CCS = complex complex struct without an alias |
||||
|
CCS = complex complex struct |
||||
|
ACCS = alias of a complex complex struct |
||||
|
|
||||
|
Nested structs |
||||
|
-------------- |
||||
|
there is always a hosting struct and a nesting struct |
||||
|
in case of double nesting it can be both |
||||
|
|
||||
|
Simply nested struct [ primitive | complex ] |
||||
|
-------------------------------------------- |
||||
|
(aliased) hosting struct (complex always) |
||||
|
_HS = hosting struct without an alias |
||||
|
HS = hosting struct |
||||
|
AHS = alias of a hosting struct |
||||
|
_NPS = nested primitive struct without an alias |
||||
|
_NCS = nested complex struct without an alias |
||||
|
|
||||
|
Doubly nested struct (complex always) |
||||
|
------------------------------------- |
||||
|
_HHS = hosting hosting struct without an alias |
||||
|
HHS = hosting hosting struct |
||||
|
AHHS = alias of a hosting hosting struct |
||||
|
_NHS = nested hosting struct |
||||
|
_NNPS = nested nested struct |
||||
|
_NNCS = nested nested complex struct |
||||
|
|
||||
|
enums in structs |
||||
|
_NEHS = nested enum in hosting struct |
||||
|
_NENHS = nested enum in nested hosting struct |
||||
|
|
||||
|
|
||||
|
|
||||
|
Enums |
||||
|
===== |
||||
|
Enums only have the item qualifier I and A, |
||||
|
so their combinations are simple. |
||||
|
|
||||
|
Covered combinations |
||||
|
==================== |
||||
|
_IE = incomplete enum without an alias |
||||
|
IE = incomplete enum |
||||
|
AIE = alias of an incomplete enum |
||||
|
_E = enum without an alias |
||||
|
E = enum |
||||
|
AE = alias of an enum |
||||
|
|
||||
|
|
||||
|
Typedefs |
||||
|
======== |
||||
|
Typedefs are simply applied to all defined enums and structs, and the |
||||
|
their respective "alias". |
||||
|
Then a typedef os applied to every typedef (TT*) |
||||
|
|
||||
|
|
@ -1,4 +1,4 @@ |
|||||
#include "test_lib.h" |
#include "lib_test.h" |
||||
|
|
||||
struct _PS func__PS_V() { |
struct _PS func__PS_V() { |
||||
return var__PS; |
return var__PS; |
@ -0,0 +1,10 @@ |
|||||
|
#ifndef MAIN_INCLUDE_H |
||||
|
#define MAIN_INCLUDE_H |
||||
|
|
||||
|
#include "typedefs.h" |
||||
|
#include "enums.h" |
||||
|
#include "structs.h" |
||||
|
#include "functions.h" |
||||
|
#include "vars.h" |
||||
|
|
||||
|
#endif //MAIN_INCLUDE_H
|
@ -1,9 +1,9 @@ |
|||||
#include "test_lib.h" |
#include "lib_test.h" |
||||
#include <stdio.h> |
#include <stdio.h> |
||||
|
|
||||
|
|
||||
int main() { |
int main() { |
||||
printf("test_lib starting...\n"); |
printf("lib_test starting...\n"); |
||||
|
|
||||
|
|
||||
TT_HHS a; |
TT_HHS a; |
@ -1,110 +0,0 @@ |
|||||
#ifndef MAIN_INCLUDE_H |
|
||||
#define MAIN_INCLUDE_H |
|
||||
|
|
||||
#include "typedefs.h" |
|
||||
#include "enums.h" |
|
||||
#include "structs.h" |
|
||||
#include "functions.h" |
|
||||
#include "vars.h" |
|
||||
|
|
||||
// Gen-CID
|
|
||||
// =======
|
|
||||
// Gen-CID generates a C Interface Defintion file (json) given the inputs:
|
|
||||
// * headerfile
|
|
||||
// * list of function names needed
|
|
||||
// * list of var names needed
|
|
||||
// The generator searches each function/var in the headerfile (recursively) and collects all the
|
|
||||
// types needed (var type, return type, parm types).
|
|
||||
// As structs can contain further types, these dependent types need to be collected
|
|
||||
// recursively.
|
|
||||
// Finally, all the collected types will be resolved to their final underlying type.
|
|
||||
// If a type is primitive, nothing needs to be done, cause its already defined.
|
|
||||
// But types of typekind struct or enum need to be defined.
|
|
||||
// Their definition will be searched for in the headerfile and included in the interface definition
|
|
||||
// The CID file contains all the information needed to represent:
|
|
||||
// * functions
|
|
||||
// * vars
|
|
||||
// * structs
|
|
||||
// * enums
|
|
||||
// Well enough so they can be expressed in pyBind11
|
|
||||
// use "pyBind11-CID" to generate the pyBind11 code out of the CID file.
|
|
||||
//
|
|
||||
// Gen-CID test library
|
|
||||
// --------------------
|
|
||||
// This here is the test main test library for Gen-CID.
|
|
||||
// The C language is broken down into its components and common pattern.
|
|
||||
// It is a humble attempt to cover all possible combinations that can be created in the
|
|
||||
// C language. (like, struct containing` primitive, struct containing struct, typedef chains,
|
|
||||
// etc..).
|
|
||||
// Please note, that pointer types have not been addressed yet (at all)
|
|
||||
//
|
|
||||
// The intended use of this test lib is: If you encounter a scenario using Gen-CID that poses problem
|
|
||||
// it is most likely that the scenario can be reproduced using this test lib pretty easily.
|
|
||||
// lets say you Gen-CID a function with sig:
|
|
||||
// TT_E(*)(ACCS), where:
|
|
||||
// TT_E = typedef of typedef of an enum without an alias.
|
|
||||
// ACCS = Alias to a complex struct containing another complex struct
|
|
||||
// these types exist already along with a systematic permutation of possible types that amount
|
|
||||
// to over 100 of types.
|
|
||||
// just write your func/var using these types and debug the generation.
|
|
||||
|
|
||||
|
|
||||
// The CID format deals with items. Everything is an item.
|
|
||||
// There are qualifiers that can be used and combined to define an item. (list below)
|
|
||||
// e.g PS = primitive struct that possibly has a typedef
|
|
||||
//
|
|
||||
// Of all the possible combinations, not all are valid (C lang). Its a futile attempt
|
|
||||
// trying to cover all the valid ones. But an effort has been made to cover the most
|
|
||||
// of the valid combinations.
|
|
||||
// Combination of structs, enums and typedefs are systematically explored in the files:
|
|
||||
// * structs.h
|
|
||||
// * enums.h
|
|
||||
// * typedefs.h
|
|
||||
//
|
|
||||
// For all the types defined the file:
|
|
||||
// * vars.h
|
|
||||
// contains an instance of each.
|
|
||||
//
|
|
||||
// for all the possible function signature, well with a 100 types,
|
|
||||
// we can create 10000 different sigantures using 1 ret and 1 arg.
|
|
||||
// Therefore, no functions have been defined.
|
|
||||
// define them when you are interested in the combination, and Gen-CID the defintion.
|
|
||||
|
|
||||
|
|
||||
// Item Qualitfier
|
|
||||
// ===============
|
|
||||
// V = Void already defined
|
|
||||
// P = Primitive Type already defined
|
|
||||
// S = Struct -> struct.h
|
|
||||
// E = Enum -> enums.h
|
|
||||
// A = Alias -> structs.h/enums.h
|
|
||||
// N = Nested (Structs only, cant be aliased) -> structs.h
|
|
||||
// H = Hosting (Structs only -> structs.h
|
|
||||
// containing the nested struct, cant be primitive)
|
|
||||
// T = typedef -> typedefs.h
|
|
||||
// I = Incomplete / (forward decl) -> struct.h/enums.h
|
|
||||
//
|
|
||||
// func_ = function -> functions.h
|
|
||||
// var_ = variable -> vars.h
|
|
||||
//
|
|
||||
// prefixed underline (e.g _E) means no typedef/alias exists for this item (enum in this case)
|
|
||||
//
|
|
||||
// Alias vs. Typedef
|
|
||||
// -----------------
|
|
||||
// aliased means direct typedef directly, like
|
|
||||
// structs and enums only
|
|
||||
/*
|
|
||||
* typedef struct _X { |
|
||||
int x; |
|
||||
* } X; |
|
||||
* |
|
||||
*/ |
|
||||
|
|
||||
// Typedef means, not typdeffed directly, but anywhere, like
|
|
||||
/*
|
|
||||
* typedef _X X; |
|
||||
* |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
#endif //MAIN_INCLUDE_H
|
|
@ -1,59 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
# This file is under GNU Affero General Public License 3.0 |
|
||||
# see LICENSE.txt |
|
||||
|
|
||||
from . import c_2_ast |
|
||||
from . import ast_2_cid |
|
||||
from . import cid_2_yml |
|
||||
from . import utils |
|
||||
|
|
||||
import os |
|
||||
|
|
||||
|
|
||||
class CIDTools: |
|
||||
|
|
||||
def __init__(self, libclang_path, header_filename, pymodule_name, out_dir=None): |
|
||||
self.header = self._create_header(header_filename, out_dir) |
|
||||
self.c2ast = c_2_ast.C2AST(libclang_path) |
|
||||
self.pymodule_name = pymodule_name |
|
||||
|
|
||||
# out-dir is in-dir if not specified |
|
||||
def _create_header(self, path, out_dir=None): |
|
||||
header = {"path": "", |
|
||||
"dir": "", |
|
||||
"filename": "", |
|
||||
"out_dir": "", |
|
||||
"sourcecode": "", |
|
||||
"ast": "", |
|
||||
"cid": "", |
|
||||
"yml": ""} |
|
||||
|
|
||||
header["path"] = path |
|
||||
header["dir"] = os.path.dirname(path) |
|
||||
header["filename"] = os.path.basename(path) |
|
||||
|
|
||||
header["out_dir"] = header["dir"] |
|
||||
if out_dir: |
|
||||
header["out_dir"] = out_dir |
|
||||
|
|
||||
header["sourcecode"] = utils.read_file(path) |
|
||||
return header |
|
||||
|
|
||||
|
|
||||
def extract(self, var_names, func_names, debug_ast=False, debug_cid=False, debug_yml=False): |
|
||||
# ast |
|
||||
self.header["ast"] = self.c2ast.parse(self.header["path"], follow_includes=True) |
|
||||
if debug_ast: |
|
||||
utils.write_json(self.header["ast"], self.header["out_dir"] + "/" + self.header["filename"] + ".ast.json") |
|
||||
|
|
||||
# cid |
|
||||
self.header["cid"] = ast_2_cid.extract_cid_selectively(self.header["ast"], var_names, func_names) |
|
||||
if debug_cid: |
|
||||
utils.write_json(self.header["cid"], self.header["out_dir"] + "/" + self.header["filename"] + ".cid.json") |
|
||||
|
|
||||
# yml |
|
||||
self.header["yml"] = cid_2_yml.generate_yml(self.header["cid"], self.pymodule_name) |
|
||||
if debug_yml: |
|
||||
utils.write_string(self.header["yml"], self.header["out_dir"] + "/" + self.header["filename"] + ".cid.yml") |
|
||||
|
|
||||
return self.header |
|
@ -0,0 +1,58 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# This file is under GNU Affero General Public License 3.0 |
||||
|
# see LICENSE.txt |
||||
|
|
||||
|
from . import c_2_ast |
||||
|
from . import ast_2_acid |
||||
|
from . import acid_yml |
||||
|
from . import utils |
||||
|
|
||||
|
import os |
||||
|
|
||||
|
|
||||
|
class pEpACIDGen: |
||||
|
|
||||
|
def __init__(self, libclang_path, header_filename, pymodule_name, out_dir=None): |
||||
|
self.model = self._acid_model_create(header_filename, out_dir) |
||||
|
self.c2ast = c_2_ast.C2AST(libclang_path) |
||||
|
self.pymodule_name = pymodule_name |
||||
|
|
||||
|
# out-dir is in-dir if not specified |
||||
|
def _acid_model_create(self, path, out_dir=None): |
||||
|
model = {"path": "", |
||||
|
"dir": "", |
||||
|
"filename": "", |
||||
|
"out_dir": "", |
||||
|
"sourcecode": "", |
||||
|
"ast": "", |
||||
|
"acid": "", |
||||
|
"acid_yml": ""} |
||||
|
|
||||
|
model["path"] = path |
||||
|
model["dir"] = os.path.dirname(path) |
||||
|
model["filename"] = os.path.basename(path) |
||||
|
|
||||
|
model["out_dir"] = model["dir"] |
||||
|
if out_dir: |
||||
|
model["out_dir"] = out_dir |
||||
|
|
||||
|
model["sourcecode"] = utils.read_file(path) |
||||
|
return model |
||||
|
|
||||
|
def extract(self, var_names, func_names, debug_ast=False, debug_acid=False, debug_yml=False): |
||||
|
# ast |
||||
|
self.model["ast"] = self.c2ast.parse(self.model["path"], follow_includes=True) |
||||
|
if debug_ast: |
||||
|
utils.write_json(self.model["ast"], self.model["out_dir"] + "/" + self.model["filename"] + ".ast.json") |
||||
|
|
||||
|
# acid |
||||
|
self.model["acid"] = ast_2_acid.extract_acid_selectively(self.model["ast"], var_names, func_names) |
||||
|
if debug_acid: |
||||
|
utils.write_json(self.model["acid"], self.model["out_dir"] + "/" + self.model["filename"] + ".acid.json") |
||||
|
|
||||
|
# yml |
||||
|
self.model["acid_yml"] = acid_yml.generate_acid_yml(self.model["acid"], self.pymodule_name) |
||||
|
if debug_yml: |
||||
|
utils.write_string(self.model["acid_yml"], self.model["out_dir"] + "/" + self.model["filename"] + ".acid.yml") |
||||
|
|
||||
|
return self.model |
Loading…
Reference in new issue