diff --git a/src/bindings/c/README.md b/src/bindings/c/README.md new file mode 100644 index 00000000000..4a9e18e30fc --- /dev/null +++ b/src/bindings/c/README.md @@ -0,0 +1,51 @@ +# OpenVINO C API + +OpenVINO C API is a key part of the OpenVINO extension for C API users. This component provides C API for OpenVINO Toolkit. + +```mermaid +flowchart LR + c_application[("C Application")] + openvino_c{{openvino::c}} + openvino{{openvino}} + + style c_application fill:#427cb0 + style openvino_c fill:#6c9f7f + style openvino fill:#6c9f7f + + c_application-->openvino_c-->openvino +``` + +OpenVINO C API uses [the common coding style rules](../../../docs/dev/coding_style.md). + +## Key contacts + +People from the [openvino-c-api-maintainers](https://github.com/orgs/openvinotoolkit/teams/openvino-c-api-maintainers) group have the rights to approve and merge PRs to the C API component. They can assist with any questions about C API component. + +## Components + +OpenVINO C API has the following structure: + * [docs](./docs) contains developer documentation for OpenVINO C APIs. + * [include](./include) contains all provided C API headers. [Learn more](https://docs.openvino.ai/latest/api/api_reference.html). + * [src](./src) contains the implementations of all C APIs. + * [tests](./tests) contains all tests for OpenVINO C APIs. [Learn more](./docs/how_to_write_unit_test.md). + +> **NOTE**: Using API 2.0 is strongly recommended. Legacy API (for C) [header file](./include/c_api/ie_c_api.h), [source file](./src/ie_c_api.cpp), [unit test](./tests/ie_c_api_test.cpp) are also included in the component, but the legacy API is no longer extended. + +## Tutorials + +* [How to integrate OpenVINO C API with Your Application](https://docs.openvino.ai/latest/openvino_docs_OV_UG_Integrate_OV_with_your_application.html) +* [How to wrap OpenVINO objects with C](./docs/how_to_wrap_openvino_objects_with_c.md) +* [How to wrap OpenVINO interfaces with C](./docs/how_to_wrap_openvino_interfaces_with_c.md) +* [Samples implemented by OpenVINO C API](../../../samples/c/) +* [How to debug C API issues](./docs/how_to_debug_c_api_issues.md) +* [How to write unit test](./docs/how_to_write_unit_test.md) + +## How to contribute to the OpenVINO repository + +See [CONTRIBUTING](../../../CONTRIBUTING.md) for details. + +## See also + + * [OpenVINO™ README](../../../README.md) + * [OpenVINO Runtime C API User Guide](https://docs.openvino.ai/latest/openvino_docs_OV_UG_Integrate_OV_with_your_application.html) + * [Migration of OpenVINO C API](https://docs.openvino.ai/latest/openvino_2_0_transition_guide.html) diff --git a/src/bindings/c/docs/how_to_debug_c_api_issues.md b/src/bindings/c/docs/how_to_debug_c_api_issues.md new file mode 100644 index 00000000000..af9aabc71ce --- /dev/null +++ b/src/bindings/c/docs/how_to_debug_c_api_issues.md @@ -0,0 +1,14 @@ +# How to Debug C API Issues + +C API provides exception handling, here are all possible return values of the functions: + +https://github.com/openvinotoolkit/openvino/blob/d96c25844d6cfd5ad131539c8a0928266127b05a/src/bindings/c/include/openvino/c/ov_common.h#L68-L96 + +There are two main types of possible issues: +* parameter checking issue: return value is -14, check the input parameters +* C++ call exception issue: if C++ called by C interface throw exception, C interface will catch the exception but no throw to C user, just returns the status value, without a detailed message. If you want details, can print it in exception macro. + + ## See also + * [OpenVINO™ README](../../../../README.md) + * [C API developer guide](../README.md) + * [OpenVINO Debug Capabilities](../../../../docs/dev/debug_capabilities.md) diff --git a/src/bindings/c/docs/how_to_wrap_openvino_interfaces_with_c.md b/src/bindings/c/docs/how_to_wrap_openvino_interfaces_with_c.md new file mode 100644 index 00000000000..5afb1fc1375 --- /dev/null +++ b/src/bindings/c/docs/how_to_wrap_openvino_interfaces_with_c.md @@ -0,0 +1,81 @@ +# How to wrap OpenVINO interfaces with C + +The library `openvino_c` implements most C++ interfaces provided in OpenVINO with C. +This page describes how to wrap C++ interfaces from OpenVINO to C interfaces: + 1) Define C interface name and input parameters + 2) Check the validation of input parameters + 3) Convert C input parameters to C++ interface parameters + 4) Call C++ interface and get return object + 5) Convert C++ return object to C object + +```mermaid +flowchart LR + subgraph c_wrap_process[Wrapping C++ by C Flow] + c_interface["Define C name"] + c_check_parameter["Input parameter checking"] + c_return_invalid["return ov_status_e::INVALID_C_PARAM"] + + subgraph c_wrap_call_cpp[Try Call C++] + c_parameter_convert["convert C parameters to C++ parameters"] + c_call_cpp_interface["call C++ interface"] + cpp_parameter_convert["convert C++ returned objects to C object"] + end + + c_return_success["return ov_status_e::OK"] + c_return_exception["catch EXCEPTION and return"] + + c_interface-->c_check_parameter + + c_check_parameter--valid-->c_parameter_convert + c_check_parameter--invalid-->c_return_invalid + + c_parameter_convert-->c_call_cpp_interface + c_call_cpp_interface-->cpp_parameter_convert + + cpp_parameter_convert-->c_return_success + c_wrap_call_cpp-->c_return_exception + end +``` + +All C-provided interfaces can be classified into three types of methods: +- Wrap C++ interface to create an object +- Wrap C++ interface to operate an object +- Interfaces implemented by C + +## Wrap C++ interface to create an object +Like the C++ programming create `class` instance, C also need to create related object such as creating `ov::Core`, `ov::Model`, `ov::InferRequest` and so on. C wrap this operation directly and save a shared pointer to the object(C++) back to C `struct` object. Based on the above wrapping method, example about creating `ov::Core` instance will be introduction for more details to illustrate how to wrap C++ interfaces. + +Thinking about the C++ interface: + +https://github.com/openvinotoolkit/openvino/blob/d96c25844d6cfd5ad131539c8a0928266127b05a/src/inference/include/openvino/runtime/core.hpp#L46-L58 + +C wrap as following: + +https://github.com/openvinotoolkit/openvino/blob/d96c25844d6cfd5ad131539c8a0928266127b05a/src/bindings/c/src/ov_core.cpp#L48-L64 + +Because the C++ core create API has default parameter `const std::string& xml_config_file = {}`, C has to create two APIs for it. For default parameter missing case, C calls the func with default parameter but value is NULL. So the following introduction focus on the func with default parameter. The first define the API name `ov_core_create_with_config` and than do the input parameters checking. For core creates no need C parameters convert to C++, call C++ API directly and make a shared pointer `std::make_shared(xml_config_file)`. Than get result from C++ call and save to C object `*core = _core.release()`. If no error, return success `return ov_status_e::OK;`. Note that almost all C interfaces pass a pointer parameter to save result, which also need to be freed after use. + +## Wrap C++ interface to operate object +C++ interface provides many ways to operate instances, such as set/get property for core, infer request do infer, get info from model and so on. C also need provides those related operations. Here is an example about doing inference: + +https://github.com/openvinotoolkit/openvino/blob/d96c25844d6cfd5ad131539c8a0928266127b05a/src/bindings/c/src/ov_infer_request.cpp#L236-L247 + +This interface call C++ API directly without return value need to save. But need to note the input parameter, which is a C `struct` pointer for providing operation object. + +## C implement interface +To provide more convenience for C users, C implements some C++ class by rewriting including `shape`, `dimension`, `partial shape` and so on. Because of this, C also implements some interface to create/operate C `struct` objects, which also needs the conversion from C object to C++ object before C++ call. + +For example, the C `shape` created by + +https://github.com/openvinotoolkit/openvino/blob/d96c25844d6cfd5ad131539c8a0928266127b05a/src/bindings/c/src/ov_shape.cpp#L17-L33 + +As we can see no C++ interface called. But when the object needs to be used for C++ call, which will provide info to create the related C++ object before call, such as: + +https://github.com/openvinotoolkit/openvino/blob/d96c25844d6cfd5ad131539c8a0928266127b05a/src/bindings/c/src/ov_tensor.cpp#L41-L55 + +The tensor create needs to specify the shape info, so C shape need to be converted to C++ class before C++ interface using. Vice versa, the object needs to convert to C rewriting object for C users convenience. + + ## See also + * [OpenVINO™ README](../../../../README.md) + * [C API developer guide](../README.md) + * [C API Reference](https://docs.openvino.ai/latest/api/api_reference.html) diff --git a/src/bindings/c/docs/how_to_wrap_openvino_objects_with_c.md b/src/bindings/c/docs/how_to_wrap_openvino_objects_with_c.md new file mode 100644 index 00000000000..11d1af83f2a --- /dev/null +++ b/src/bindings/c/docs/how_to_wrap_openvino_objects_with_c.md @@ -0,0 +1,76 @@ +# How to wrap OpenVINO objects with C + +Here is the details about how to wrap objects(C++) form OpenVINO to objects(C). + +In OpenVINO C++ implementation, many objects are defined with `class`, such as `ov::Core`, `ov::Model`, `ov::InferRequest`..., but for C `class` doesn't be supported. So, C need to create new object to represent those objects. Three kinds of methods had been adopted in our implementation: + * C `struct` contains a shared pointer to C++ `class`, [Wrap by C++ Shared Pointer](#wrap_by_c++_shared_pointer) + * C `struct` contains a instance of C++ `class`, [Wrap by C++ Object](#wrap_by_c++_object) + * C `struct` rewrite the C++ `class`, [Wrap by Rewrite](#wrap_by_rewrite) + +Tips: +1) For the objects which needs to be hided for users, C `struct` contains a shared pointer will be adopted. +2) For the objects which needs to be created, operated and read by users, rewrite the C++ `class` will be better. +3) For some simple objects, C `struct` contains a instance of C++ `class` will be enough. + + ## Wrap by C++ Shared Pointer + +C construct a new `struct` represents the class, which contains a shared pointer to the `class` as following: + +``` +struct ov_class_name { + std::shared_ptr object; +}; +``` + +Here is an example (core) for wrapping by shared pointer: + +https://github.com/openvinotoolkit/openvino/blob/d96c25844d6cfd5ad131539c8a0928266127b05a/src/inference/include/openvino/runtime/core.hpp#L41-L684 + +Represent by C `struct`: + +https://github.com/openvinotoolkit/openvino/blob/d96c25844d6cfd5ad131539c8a0928266127b05a/src/bindings/c/src/common.h#L47-L53 + +C provides the `struct` by `typedef struct ov_core ov_core_t;` + + ## Wrap by C++ Object + +C construct a new `struct` represents the class, which contains an instance to C++ `class` as following: + +``` +struct ov_ClassName { + ov::ClassName object; +}; +``` + +Here is an example (layout) for wrapping by shared pointer: + +https://github.com/openvinotoolkit/openvino/blob/d96c25844d6cfd5ad131539c8a0928266127b05a/src/core/include/openvino/core/layout.hpp#L44-L107 + +Represent by C `struct`: + +https://github.com/openvinotoolkit/openvino/blob/d96c25844d6cfd5ad131539c8a0928266127b05a/src/bindings/c/src/common.h#L95-L101 + +C provides the `struct` by `typedef struct ov_layout ov_layout_t;` + + ## Wrap by Rewrite + +C construct a new `struct` represents the class, which rewrites related info to the `class` as following: + +``` +typedef struct { + ov::ClassName object; +} ov_class_name_t; +``` +Here is an example (shape) for wrapping by shared pointer: +https://github.com/openvinotoolkit/openvino/blob/d96c25844d6cfd5ad131539c8a0928266127b05a/src/core/include/openvino/core/shape.hpp#L21-L40 + +Represent by C `struct` [here](../src/common.h) + +https://github.com/openvinotoolkit/openvino/blob/d96c25844d6cfd5ad131539c8a0928266127b05a/src/bindings/c/include/openvino/c/ov_shape.h#L15-L22 + +> **NOTE**: this implementation needs developer create the C++ `class` based on the C `struct` info in using this rewrite type. + + ## See also + * [OpenVINO™ README](../../../../README.md) + * [C API developer guide](../README.md) + * [C API Reference](https://docs.openvino.ai/latest/api/api_reference.html) \ No newline at end of file diff --git a/src/bindings/c/docs/how_to_write_unit_test.md b/src/bindings/c/docs/how_to_write_unit_test.md new file mode 100644 index 00000000000..d1f4a83d6c2 --- /dev/null +++ b/src/bindings/c/docs/how_to_write_unit_test.md @@ -0,0 +1,18 @@ +# How to Write Unit Test for C API + +To ensure the accuracy of C API, all interfaces need to implement function level unit test at least. According to the object define, all implemented unit test cases are located in this folder. + +The generated binary `ov_capi_test` included the unit cases about all implemented C API interfaces. + +If developer wrap new interfaces from OpenVINO C++, you also need to add the unit test case in the correct location. +Here is an example wrap C++ interface to C [wrap core](./how_to_wrap_openvino_interfaces_with_c.md). + +Create unit test case for this interface. At first, this interface is for core operation so the location should at [ov_core_test.cpp](../tests/ov_core_test.cpp). Also, the interface has default parameter so need to make unit test case for parameter missing. The final based function level test like: + +https://github.com/openvinotoolkit/openvino/blob/d96c25844d6cfd5ad131539c8a0928266127b05a/src/bindings/c/tests/ov_core_test.cpp#L39-L63 + +## See also + * [OpenVINO™ README](../../../../README.md) + * [C API developer guide](../README.md) + * [C API Reference](https://docs.openvino.ai/latest/api/api_reference.html) +