Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 31 additions & 9 deletions bindgen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ def _filter_module(m):
)


def toposort_modules(modules, module_settings):
def module_deps(modules, module_settings):

deps = {}

Expand All @@ -599,14 +599,30 @@ def toposort_modules(modules, module_settings):
)

# iterate over all classes, templates and typedefs
deps[m.name] = set(
cls_dict[s]
for c in m.classes + m.class_templates + typedefs
for s in c.superclass
if s in cls_dict
) | custom_deps - {m.name}
deps[m.name] = (
set(
cls_dict[s]
for c in m.classes + m.class_templates + typedefs
for s in c.superclass
if s in cls_dict
)
| custom_deps
) - {m.name}

return toposort_flatten(deps)
return deps


def collections_deps(modules, collection_pat):
# owners of the superclasses of the collection class templates
cls_dict = {c.name: m.name for m in modules for c in m.classes}
templates = [
t
for m in modules
for t in m.class_templates
if t.name.startswith(collection_pat)
]

return {cls_dict[s] for t in templates for s in t.superclass if s in cls_dict}


def render(
Expand Down Expand Up @@ -678,6 +694,8 @@ def proper_delete_operator(cls):
for c in collections:
collection_types |= set(c.leaf_args())

deps = module_deps(modules, module_settings)

jinja_env.globals.update(
{
"contains_string": lambda s, pats: any(
Expand Down Expand Up @@ -714,7 +732,11 @@ def proper_delete_operator(cls):
"proper_new_operator": proper_new_operator,
"proper_delete_operator": proper_delete_operator,
"module_names": module_names,
"sorted_modules": toposort_modules(modules, module_settings),
"sorted_modules": toposort_flatten(deps),
"module_deps": deps,
"collections_deps": collections_deps(
modules, settings["collection_pattern"]
),
"settings": settings,
"collection_types": collection_types,
"exclude_collections": exclude_collections,
Expand Down
2 changes: 2 additions & 0 deletions bindgen/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@
Optional("byref_types", default=[]): [str],
Optional("byref_types_smart_ptr", default=[]): [str],
Optional("parsing_header", default=""): str,
# members of a package registered on first use; needs lazy::desc and lazy::install from include_pre
Optional("lazy", default=False): bool,
Optional("collection_pattern", default=None): str,
Optional("exclude_collection", default=[]): [str],
Optional("collection_include_header_pre", default=None): str,
Expand Down
48 changes: 36 additions & 12 deletions bindgen/template_main.j2
Original file line number Diff line number Diff line change
Expand Up @@ -25,37 +25,61 @@ void register_collections_pre_{{i_coll}}(py::module&);
void register_collections_{{i_coll}}(py::module&);
{% endfor %}

// collection chunks wrapped so that every table row takes the main module
static void register_collections_enums(py::module &main_module) {
py::module m_coll = main_module.def_submodule("collections", R"#(Artifical module with instantiated collection types)#");
{% for i_coll in range(N_coll_chunks) %}
register_collections_pre_{{i_coll}}(m_coll);
{% endfor %}
}

static void register_collections(py::module &main_module) {
py::module m_coll = static_cast<py::module>(main_module.attr("collections"));
{% for i_coll in range(N_coll_chunks) %}
register_collections_{{i_coll}}(m_coll);
{% endfor %}
}

{% if settings['lazy'] %}
static const lazy::desc {{name}}_modules[] = {
{% for mod in sorted_modules %}
{"{{mod}}", &register_{{mod}}_enums, &register_{{mod}}, "{{ module_deps[mod]|sort|join(',') }}"},
{% endfor %}
{"collections", &register_collections_enums, &register_collections, "{{ collections_deps|sort|join(',') }}"},
};
{% endif %}

// main module definiiton
PYBIND11_MODULE({{name}}, m) {

{% if settings['lazy'] %}
// phase 1 of every package
for (const auto &d : {{name}}_modules) d.enums(m);
{% else %}
// register submodules

{% for mod in sorted_modules %}
register_{{mod}}_enums(m);
{% endfor %}

// define the collections module
py::module m_coll = m.def_submodule("collections", R"#(Artifical module with instantiated collection types)#");

// preregister collections
{% for i_coll in range(N_coll_chunks) %}
register_collections_pre_{{i_coll}}(m_coll);
{% endfor %}

register_collections_enums(m);
// register modules
{% for mod in sorted_modules %}
register_{{mod}}(m);
{% endfor %}
{% endif %}

// Add attributes if present

{% for k,v in settings['Attributes'].items() %}
m.attr("{{k}}") = py::cast("{{v}}");
{% endfor %}

{% if settings['lazy'] %}
// phase 2: per package on first use
lazy::install(m, {{name}}_modules);
{% else %}
// register collection types
{% for i_coll in range(N_coll_chunks) %}
register_collections_{{i_coll}}(m_coll);
{% endfor %}
register_collections(m);
{% endif %}

}
19 changes: 0 additions & 19 deletions bindgen/template_sub.j2
Original file line number Diff line number Diff line change
Expand Up @@ -89,20 +89,6 @@ auto {{ns}} = static_cast<py::module>(m.attr("{{ns}}"));
register_default_constructor<{{c.name}} {{pointer(c)}}>({{mod}},"{{cls_name(c)}}");
{% endif %}

// nested enums
{% for enum in c.enums %}
{% if enum.anonymous %}
{% for val in enum.values %}
klass.attr("{{ val | replace("None", "None_")}}") = py::cast(int({{ enum.name+"::" if enum.name}}{{ val }}));
{% endfor %}
{% else %}
py::enum_<{{enum.name}}>(klass, "{{ enum.name.split('::')[-1] + '_e' }}", R"#({{enum.comment}})#")
{% for val in enum.values %}
.value("{{val | replace("None", "None_")}}", {{enum.name}}::{{val}}){{ ";" if loop.last }}
{% endfor %}
{% endif %}
{% endfor %}

static_cast<py::class_<{{c.name}} {{pointer(c)}} {% if c.abstract %},Py_{{c.name}}{% endif %} {{super(c,class_dict,module.typedef_dict)}}>>(klass)
// constructors
{% for i,con in enumerate(c.constructors) %}
Expand Down Expand Up @@ -277,11 +263,6 @@ auto m{{ns}} = static_cast<py::module>(m.attr("{{ns}}"));
{% endfor %}


// exceptions
{% for ex in module.exceptions %}
register_occ_exception<{{ex.name}}>(m, "{{ex.name}}");
{% endfor %}

// user-defined post-inclusion per module in the body
{% if module_settings['include_body_post'] %}
{{ module_settings['include_body_post'] }}
Expand Down
23 changes: 23 additions & 0 deletions bindgen/template_sub_pre.j2
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ void register_{{module.name}}_enums(py::module &main_module) {


py::module m = main_module.def_submodule("{{module.name}}", R"#({{module.doc}})#");
py::object klass;

// add namespaces as submodules
{% for ns in module.namespaces %}
Expand Down Expand Up @@ -118,6 +119,28 @@ auto {{ns}} = m.def_submodule("{{ns}}");
preregister_template_{{spec.base}}<{{spec.args|join(',')}}>(m, "{{name}}");
{% endfor %}

// nested enums
{% for c in module.classes %}{% if c.enums and ((proper_new_operator(c) and proper_delete_operator(c)) or 'Standard_Transient' in c.rootclass) %}
klass = {{ "m" if not c.namespaces else c.namespaces[0] }}.attr("{{cls_name(c)}}");
{% for enum in c.enums %}
{% if enum.anonymous %}
{% for val in enum.values %}
klass.attr("{{ val | replace("None", "None_")}}") = py::cast(int({{ enum.name+"::" if enum.name}}{{ val }}));
{% endfor %}
{% else %}
py::enum_<{{enum.name}}>(klass, "{{ enum.name.split('::')[-1] + '_e' }}", R"#({{enum.comment}})#")
{% for val in enum.values %}
.value("{{val | replace("None", "None_")}}", {{enum.name}}::{{val}}){{ ";" if loop.last }}
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}{% endfor %}

// exceptions
{% for ex in module.exceptions %}
register_occ_exception<{{ex.name}}>(m, "{{ex.name}}");
{% endfor %}

// user-defined post-inclusion per module in the body
{% if module_settings['preregister_include_body_post'] %}
{{ module_settings['preregister_include_body_post'] }}
Expand Down