Commit 7381de43 authored by tao558's avatar tao558
Browse files

wrapper_input files use YAML

parent de7c9966
......@@ -33,25 +33,25 @@ function(_autopybind11_get_compiler_flags)
endfunction()
function(_autopybind11_get_sources)
set(PreProcessOneValueArgs JSON_INPUT DESTINATION GENERATED_SOURCES)
set(PreProcessOneValueArgs YAML_INPUT DESTINATION GENERATED_SOURCES)
set(PYBIND_RUN_NAME ${ARGV0})
cmake_parse_arguments(PARSE_ARGV 1 PYBIND_RUN "" "${PreProcessOneValueArgs}" "")
execute_process(COMMAND ${PYTHON_EXECUTABLE} ${AutoPyBind11_generator} "-j" ${PYBIND_RUN_JSON_INPUT}
"-o" ${PYBIND_RUN_DESTINATION}
"--module_name" "${PYBIND_RUN_NAME}"
-n
execute_process(COMMAND ${PYTHON_EXECUTABLE} ${AutoPyBind11_generator} "-y" ${PYBIND_RUN_YAML_INPUT}
"-o" ${PYBIND_RUN_DESTINATION}
"--module_name" "${PYBIND_RUN_NAME}"
-n
OUTPUT_VARIABLE sources OUTPUT_STRIP_TRAILING_WHITESPACE)
set(${PYBIND_RUN_GENERATED_SOURCES} ${sources} PARENT_SCOPE)
endfunction()
function(autopybind11_add_module)
set(generateOneValueArgs JSON_INPUT CONFIG_INPUT DESTINATION NAMESPACE C_STD_FLAG)
set(generateOneValueArgs YAML_INPUT CONFIG_INPUT DESTINATION NAMESPACE C_STD_FLAG)
set(generateMultiValueArgs LINK_LIBRARIES FILES)
set(PYBIND_ADD_LIB_NAME ${ARGV0})
cmake_parse_arguments(PARSE_ARGV 1 PYBIND_ADD_LIB "" "${generateOneValueArgs}" "${generateMultiValueArgs}")
if(NOT PYBIND_ADD_LIB_JSON_INPUT)
message(FATAL_ERROR "JSON_INPUT must be specified")
if(NOT PYBIND_ADD_LIB_YAML_INPUT)
message(FATAL_ERROR "YAML_INPUT must be specified")
endif()
if(NOT PYBIND_ADD_LIB_LINK_LIBRARIES)
message(FATAL_ERROR "LINK_LIBRARIES must be specified")
......@@ -59,7 +59,7 @@ function(autopybind11_add_module)
if(NOT PYBIND_ADD_LIB_C_STD_FLAG)
set(PYBIND_ADD_LIB_C_STD_FLAG "-std=c++14")
endif()
_autopybind11_get_sources(${PYBIND_ADD_LIB_NAME} JSON_INPUT ${PYBIND_ADD_LIB_JSON_INPUT}
_autopybind11_get_sources(${PYBIND_ADD_LIB_NAME} YAML_INPUT ${PYBIND_ADD_LIB_YAML_INPUT}
DESTINATION ${PYBIND_ADD_LIB_DESTINATION}
GENERATED_SOURCES PYBIND_ADD_LIB_FILES)
if (PYBIND_ADD_LIB_NAMESPACE)
......@@ -74,7 +74,7 @@ function(autopybind11_add_module)
get_filename_component(tgt_helper_name ${file} NAME_WE)
# Add custom target to generate the code
# Add depends on wrapper_input.json and header files?
# Add depends on wrapper_input.YAML and header files?
# Generate file
set(PYBIND_ADD_LIB_RESPONSE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/response.rsp")
......@@ -83,27 +83,28 @@ function(autopybind11_add_module)
CONTENT "includes: ${includes}\nc_std: ${PYBIND_ADD_LIB_C_STD_FLAG}\ndefines: ${defines}")
if(PYBIND_ADD_LIB_CONFIG_INPUT AND EXISTS ${PYBIND_ADD_LIB_CONFIG_INPUT})
add_custom_command(OUTPUT ${PYBIND_ADD_LIB_FILES} wrapper.cpp COMMAND ${PYTHON_EXECUTABLE} ${AutoPyBind11_generator} -j ${PYBIND_ADD_LIB_JSON_INPUT}
add_custom_command(OUTPUT ${PYBIND_ADD_LIB_FILES} wrapper.cpp COMMAND ${PYTHON_EXECUTABLE} ${AutoPyBind11_generator}
-y ${PYBIND_ADD_LIB_YAML_INPUT}
"--module_name" ${PYBIND_ADD_LIB_NAME}
"-g" ${CastXML_EXECUTABLE}
"-cg" "${PYBIND_ADD_LIB_CONFIG_INPUT}"
"-rs" "${PYBIND_ADD_LIB_RESPONSE_DIR}"
"-o" ${PYBIND_ADD_LIB_DESTINATION}
${DEFAULT_NAMESPACE}
DEPENDS ${PYBIND_ADD_LIB_JSON}
DEPENDS ${PYBIND_ADD_LIB_YAML}
${PYBIND_ADD_LIB_CONFIG_INPUT}
${CMAKE_CURRENT_SOURCE_DIR}/response.rsp
WORKING_DIRECTORY ${PYBIND_ADD_LIB_DESTINATION})
else()
add_custom_command(OUTPUT ${PYBIND_ADD_LIB_FILES} wrapper.cpp
COMMAND ${PYTHON_EXECUTABLE} ${AutoPyBind11_generator} -j ${PYBIND_ADD_LIB_JSON_INPUT}
COMMAND ${PYTHON_EXECUTABLE} ${AutoPyBind11_generator} -y ${PYBIND_ADD_LIB_YAML_INPUT}
"--module_name" ${PYBIND_ADD_LIB_NAME}
"-g" ${CastXML_EXECUTABLE}
"-o" ${PYBIND_ADD_LIB_DESTINATION}
"-rs" "${CMAKE_CURRENT_SOURCE_DIR}/response.rsp"
${DEFAULT_NAMESPACE}
DEPENDS ${PYBIND_ADD_LIB_JSON}
DEPENDS ${PYBIND_ADD_LIB_YAML}
${CMAKE_CURRENT_SOURCE_DIR}/response.rsp
WORKING_DIRECTORY ${PYBIND_ADD_LIB_DESTINATION})
endif()
......
......@@ -30,7 +30,7 @@ C++ Setup
---------
Each directory with content to wrap should contain a file named
``wrapper_input.json``. This content should describe <filler>
``wrapper_input.yml``. This content should describe <filler>
Running the Generator
---------------------
......@@ -39,14 +39,14 @@ This script assumes that Python 3.* is used.
The Python script has help for the arguments::
$ python3 autopybind11.py -h
usage: autopybind11.py [-h] [-s SOURCE_DIR] [-j JSON_PATH] -g CASTXML_PATH
usage: autopybind11.py [-h] [-s SOURCE_DIR] [-y YAML_PATH] -g CASTXML_PATH
[--includes INCLUDES] [--no-generation] [-cg CONFIG_DIR]
optional arguments:
-h, --help show this help message and exit
-s SOURCE_DIR, --source SOURCE_DIR
-j JSON_PATH, --input_json JSON_PATH
Path to input JSON file of namespaces
-y YAML_PATH, --input_yaml YAML_PATH
Path to input YAML file of namespaces
-g CASTXML_PATH, --castxml-path CASTXML_PATH
Path to castxml
-d DEFAULT_NAMESPACE, --default_namespace DEFAULT_NAMESPACE
......
......@@ -3,7 +3,7 @@ from op_names import names_dict, arg_dependent_ops
import text_blocks as tb
import fileinput
import glob
import json
import yaml
import logging
import os
import posixpath
......@@ -388,11 +388,11 @@ class BindingsGenerator:
ret += suf
return ret
def find_module_data(self, json_dict, res_dict, free_fun_name, curr_nmspc=""):
for key in json_dict:
def find_module_data(self, yaml_dict, res_dict, free_fun_name, curr_nmspc=""):
for key in yaml_dict:
if key in ["classes", "functions", "enums"]:
is_class = key == "classes"
inner_dict = json_dict[key]
inner_dict = yaml_dict[key]
for name, data in inner_dict.items():
# First add the dependent file
res_dict["to_include"].add(data["file"])
......@@ -400,7 +400,7 @@ class BindingsGenerator:
future_file = self.find_future_file_name(is_class, name, free_fun_name, curr_nmspc)
# TODO: Could use a set, but adding this way preserves the order
# specified in the JSON files. This is important to ensure that
# specified in the yaml files. This is important to ensure that
# base classes are bound before there derived classes
if future_file not in res_dict["out_names"]:
res_dict["out_names"].append(future_file)
......@@ -416,7 +416,7 @@ class BindingsGenerator:
else: # Found a namespace. Recurse!
new_nmspc = self.add_namespace(curr_nmspc, key)
self.find_module_data(json_dict[key], res_dict, free_fun_name, new_nmspc)
self.find_module_data(yaml_dict[key], res_dict, free_fun_name, new_nmspc)
def clean_flags(self, rsp_path):
rsp_includes = []
......@@ -470,9 +470,9 @@ class BindingsGenerator:
def most_recent_namespace(self, nmspc):
return nmspc.split("::")[-1]
def generate_bindings(self, json_dict, pygccxml_data, free_fun_name="free_functions", curr_nmspc=""):
if "classes" in json_dict:
classes_dict = json_dict["classes"]
def generate_bindings(self, yaml_dict, pygccxml_data, free_fun_name="free_functions", curr_nmspc=""):
if "classes" in yaml_dict:
classes_dict = yaml_dict["classes"]
# Take this one class at a time
for class_name, class_data in classes_dict.items():
names_to_find = self.get_all_inst_names(class_name, class_data)
......@@ -483,16 +483,16 @@ class BindingsGenerator:
files_to_include = set()
all_gen_fun_data = list()
mod_name = self.most_recent_namespace(curr_nmspc) if curr_nmspc else free_fun_name
if "functions" in json_dict:
free_funs_dict = json_dict["functions"]
if "functions" in yaml_dict:
free_funs_dict = yaml_dict["functions"]
for fun_name, fun_data in free_funs_dict.items():
files_to_include.add(fun_data["file"])
gen_data_for_fun = pygccxml_data.free_functions(lambda f: f.name == fun_name)
all_gen_fun_data.extend(gen_data_for_fun)
all_gen_enum_data = list()
if "enums" in json_dict:
enums_dict = json_dict["enums"]
if "enums" in yaml_dict:
enums_dict = yaml_dict["enums"]
for enum_name, enum_data in enums_dict.items():
files_to_include.add(enum_data["file"])
gen_data_for_enum = pygccxml_data.enumeration(enum_name)
......@@ -502,10 +502,10 @@ class BindingsGenerator:
self.write_non_class_data(mod_name, all_gen_fun_data, all_gen_enum_data, self.opts.output_dir, files_to_include)
# Now check for namespaces and recurse
keys_left_to_check = set(json_dict.keys()) - {"classes", "functions", "enums"}
keys_left_to_check = set(yaml_dict.keys()) - {"classes", "functions", "enums"}
for key in keys_left_to_check:
new_nmspc = self.add_namespace(curr_nmspc, key)
self.generate_bindings(json_dict[key], pygccxml_data.namespace(key), curr_nmspc=new_nmspc)
self.generate_bindings(yaml_dict[key], pygccxml_data.namespace(key), curr_nmspc=new_nmspc)
def template_args_to_underscores(self, name):
if not name:
......@@ -567,25 +567,25 @@ class BindingsGenerator:
def parse_and_generate(self):
"""
Overall function to perform automatic generation of Pybind11 code from a C++ repository
- Parses the JSON input
- Parses the yaml input
- Generates a summary of the module
- Writes instantiations and include into "wrapper.hpp", the only input to CastXML
- Runs CastXML and uses pygccxml to read results into data object
- Walks through JSON input, writing class/function/namespace data using the generated
- Walks through yaml input, writing class/function/namespace data using the generated
information from pygccxml
:return: None
"""
# init the pygccxml stuff
# Adapted from CPPWG: https://github.com/jmsgrogan/cppwg/blob/265117455ed57eb250643a28ea6029c2bccf3ab3/cppwg/parsers/source_parser.py#L24
# Source path is the directory with the JSON in it
self.opts.source_dir = posixpath.dirname(self.opts.json_path)
# Source path is the directory with the yaml in it
self.opts.source_dir = posixpath.dirname(self.opts.yaml_path)
# Module info to be populated by find_module_data
module_info = {"to_include": set(), "class_insts": list(), "func_insts": list(), "out_names": list()}
# Generate a summary of the module
self.find_module_data(json.load(open(self.opts.json_path, "r")), module_info, "free_functions")
self.find_module_data(yaml.load(open(self.opts.yaml_path, "r")), module_info, "free_functions")
module_file = self.write_module_data(self.opts.module_name, module_info, self.opts.output_dir)
# Short circuit: prints list of files to be generated by the run, if it were to continue.
......@@ -598,14 +598,14 @@ class BindingsGenerator:
name_data = self.compile_and_parse_wrapper(rsp_includes, rsp_defs)
self.generate_bindings(json.load(open(self.opts.json_path, "r")), name_data)
self.generate_bindings(yaml.load(open(self.opts.yaml_path, "r")), name_data)
arg = ArgParser(config_file_parser_class=YAMLConfigFileParser)
arg.add("-o", "--output", action="store", dest="output_dir", required=False, default=os.getcwd())
arg.add("-j", "--input_json", action="store", dest="json_path",
help="Path to input JSON file of objects to process", required=True)
arg.add("-y", "--input_yaml", action="store", dest="yaml_path",
help="Path to input YAML file of objects to process", required=True)
arg.add("--module_name", action="store", dest="module_name",
help="Desired name of the output PyBind11 module", required=True)
arg.add("-g", "--castxml-path", action="store", dest="castxml_path",
......
......@@ -20,7 +20,7 @@ add_subdirectory(additional)
add_subdirectory(operator_testing)
add_subdirectory(multi_namespaced)
autopybind11_add_module("example" JSON_INPUT ${CMAKE_CURRENT_SOURCE_DIR}/wrapper_input.json
autopybind11_add_module("example" YAML_INPUT ${CMAKE_CURRENT_SOURCE_DIR}/wrapper_input.yml
CONFIG_INPUT ${CMAKE_CURRENT_SOURCE_DIR}/config.yml
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
LINK_LIBRARIES wrapper_example)
......
add_library(additional_example SHARED ${CMAKE_CURRENT_SOURCE_DIR}/additional.cxx ${CMAKE_CURRENT_SOURCE_DIR}/additional.hpp)
target_include_directories(additional_example PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
autopybind11_add_module("additional"
JSON_INPUT ${CMAKE_CURRENT_SOURCE_DIR}/wrapper_input.json
YAML_INPUT ${CMAKE_CURRENT_SOURCE_DIR}/wrapper_input.yml
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
LINK_LIBRARIES additional_example
)
......
......@@ -9,7 +9,7 @@ target_include_directories(multi_namespaced PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
autopybind11_fetch_build_pybind11()
autopybind11_add_module("multi_namespaced_module"
JSON_INPUT ${CMAKE_CURRENT_SOURCE_DIR}/wrapper_input.json
YAML_INPUT ${CMAKE_CURRENT_SOURCE_DIR}/wrapper_input.yml
CONFIG_INPUT ${CMAKE_CURRENT_SOURCE_DIR}/config.yml
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
LINK_LIBRARIES multi_namespaced
......
{
"classes": {
"no_nmspc_class": {
"file": "no_namespace.hpp",
"inst": [
["double","float"], ["int", "float"]
]
}
},
"functions": {
"no_nmspc_func": {
"file": "no_namespace.hpp",
"is_template": true,
"inst": [
["double","float"], ["int", "float"]
]
}
},
"first": {
"classes": {
"nmspc1_class": {
"file": "first_namespace.hpp",
"inst": [
["double","float"], ["int", "float"]
]
}
},
"functions": {
"nmspc1_func": {
"file": "first_namespace.hpp",
"is_template": true,
"inst": [
["double","float"], ["int", "float"]
]
}
},
"inner_first": {
"classes": {
"cmpnd_nmspc_class": {
"file": "compound_namespace.hpp",
"inst": [
["double","float"], ["int", "float"]
]
}
},
"functions": {
"cmpnd_nmspc_func": {
"file": "compound_namespace.hpp",
"is_template": true,
"inst": [
["double","float"], ["int", "float"]
]
}
}
}
},
"second": {
"classes": {
"nmspc2_class": {
"file": "second_namespace.hpp",
"inst": [
["double","float"], ["int", "float"]
]
}
},
"functions": {
"nmspc2_func": {
"file": "second_namespace.hpp",
"is_template": true,
"inst": [
["double","float"], ["int", "float"]
]
}
}
}
}
classes:
no_nmspc_class:
file: no_namespace.hpp
inst:
- [double, float]
- [int, float]
functions:
no_nmspc_func:
file: no_namespace.hpp
is_template: true
inst:
- [double, float]
- [int, float]
first:
classes:
nmspc1_class:
file: first_namespace.hpp
inst:
- [double, float]
- [int, float]
functions:
nmspc1_func:
file: first_namespace.hpp
is_template: true
inst:
- [double, float]
- [int, float]
inner_first:
classes:
cmpnd_nmspc_class:
file: compound_namespace.hpp
inst:
- [double, float]
- [int, float]
functions:
cmpnd_nmspc_func:
file: compound_namespace.hpp
is_template: true
inst:
- [double, float]
- [int, float]
second:
classes:
nmspc2_class:
file: second_namespace.hpp
inst:
- [double, float]
- [int, float]
functions:
nmspc2_func:
file: second_namespace.hpp
is_template: true
inst:
- [double, float]
- [int, float]
......@@ -5,7 +5,7 @@ target_include_directories(vector2 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
autopybind11_fetch_build_pybind11()
autopybind11_add_module("vector2_module"
JSON_INPUT ${CMAKE_CURRENT_SOURCE_DIR}/wrapper_input.json
YAML_INPUT ${CMAKE_CURRENT_SOURCE_DIR}/wrapper_input.yml
CONFIG_INPUT ${CMAKE_CURRENT_SOURCE_DIR}/config.yml
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
LINK_LIBRARIES vector2
......
Supports Markdown
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