Export Functions
Guide to export functions from your C++ plugin to be used by other language modules within Plugify.
In the Plugify ecosystem, C++ plugins can export functions to make them accessible to other plugins. This guide explains how to export functions in C++ and provides examples to help you integrate your plugins seamlessly.
Basic Type Mapping
The following table lists how types are exposed to the C++ API:
| C++ Type | Plugify Alias | Ref Support ? |
|---|---|---|
| void | void | ❌ |
| bool | bool | ✅ |
| char | char8 | ✅ |
| char16_t | char16 | ✅ |
| int8_t | int8 | ✅ |
| int16_t | int16 | ✅ |
| int32_t | int32 | ✅ |
| int64_t | int64 | ✅ |
| uint8_t | uint8 | ✅ |
| uint16_t | uint16 | ✅ |
| uint32_t | uint32 | ✅ |
| uint64_t | uint64 | ✅ |
| uintptr_t | ptr64 | ✅ |
| uintptr_t | ptr32 | ✅ |
| float | float | ✅ |
| double | double | ✅ |
| void* | function | ❌ |
| plg::string | string | ✅ |
| plg::any | any | ✅ |
| plg::vector<bool> | bool[] | ✅ |
| plg::vector<char> | char8[] | ✅ |
| plg::vector<char16_t> | char16[] | ✅ |
| plg::vector<int8_t> | int8[] | ✅ |
| plg::vector<int16_t> | int16[] | ✅ |
| plg::vector<int32_t> | int32[] | ✅ |
| plg::vector<int64_t> | int64[] | ✅ |
| plg::vector<uint8_t> | uint8[] | ✅ |
| plg::vector<uint16_t> | uint16[] | ✅ |
| plg::vector<uint32_t> | uint32[] | ✅ |
| plg::vector<uint64_t> | uint64[] | ✅ |
| plg::vector<uintptr_t> | ptr64[] | ✅ |
| plg::vector<uintptr_t> | ptr32[] | ✅ |
| plg::vector<float> | float[] | ✅ |
| plg::vector<double> | double[] | ✅ |
| plg::vector<plg::string> | string[] | ✅ |
| plg::vector<plg::any> | any[] | ✅ |
| plg::vector<plg::vec2> | vec2[] | ✅ |
| plg::vector<plg::vec3> | vec3[] | ✅ |
| plg::vector<plg::vec4> | vec4[] | ✅ |
| plg::vector<plg::mat4x4> | mat4x4[] | ✅ |
| plg::vec2 | vec2 | ✅ |
| plg::vec3 | vec3 | ✅ |
| plg::vec4 | vec4 | ✅ |
| plg::mat4x4 | mat4x4 | ✅ |
Exporting Functions in C++
To export a function in a C++ plugin, you need to ensure that the function is visible to other plugins. This is typically done by marking the function with the PLUGIN_API macro, which ensures the function is exported when the plugin is compiled as a dynamic link library (DLL).
Key Points
- C Linkage: The
PLUGIN_APImacro does not automatically includeextern "C"to prevent name mangling. We need ensure the function can be found just by name by addingextern "C". - Parameter and Return Types: Use Plugify's native types (e.g.,
plg::string,plg::vector) for seamless integration. - Version Script on Linux: If your build uses a version script with
local: *;(the template does, insym/version_script.lds), list every exported function underglobal:, otherwise the language module cannot find it.
Generating the PLUGIN_API Macro
The PLUGIN_API macro is generated using CMake. Here’s how you can set it up in your CMakeLists.txt file:
This generates a header file (plugin_export.h) that defines the PLUGIN_API macro. Include this header in your plugin source files to mark functions for export.
Basic Example
Here’s a simple example of exporting a function in a C++ plugin:
Function Definition
Exporting the Function
When the plugin is loaded, the function AddNumbers will be exported and can be called by other plugins.
Plugin Manifest Example
All exported functions must be described in the plugin's manifest file under the methods section. Here’s an example manifest for a plugin that exports the AddNumbers function:
Advanced Example: Exporting Complex Functions
Here’s an example of exporting a function with complex parameter and return types:
Function Definition
Plugin Manifest
Exporting Functions with References
Plugify supports reference parameters (also known as "out" or "ref" parameters) that let functions modify values and return them to the caller. In C++, reference parameters are declared with &.
Function Definition with Reference Parameters
Plugin Manifest with Reference Parameters
In the manifest, mark parameters passed by reference with "ref": true:
Reference Parameter Support
Reference parameters work with most Plugify types, as shown in the "Ref Support" column of the type mapping table. The following types do not support references:
void(cannot be passed by reference)function(callback types)
All other types, including primitives, strings, vectors and structures, support reference parameters.
Handling Callbacks
Plugify allows you to export functions that accept callbacks as parameters. Here’s an example:
Function Definition
Plugin Manifest
Automating Manifest Generation
New: You can now automate the generation of the methods section in your plugin manifest using clang-doc and a Python parser!
Instead of manually writing the manifest JSON for each exported function, you can use automated tools to extract function signatures, types, parameter descriptions, and even enum definitions directly from your C++ source code.
Benefits of Automated Generation
- No Manual JSON Writing: Function signatures are automatically extracted from your code
- Complete Type Information: Enum structures and function typedefs are included automatically
- Documentation Integration: Doxygen comments are parsed and included in the manifest
- Reduced Errors: Eliminates typos and type mismatches between code and manifest
- Easy Maintenance: Changes to function signatures are automatically reflected
Setup: Adding Documentation Generation to CMake
Add the following to your CMakeLists.txt to generate documentation and manifest JSON:
Using the Parser
Install the Parser
The parser is a Go program in the parser folder of the C++ language module. Build it with Go 1.21 or later:
A Python version with the same arguments is kept in parser/python/parser.py (needs pip install pyyaml).
Document Your Functions
Add Doxygen comments to your exported functions:
Document Enums and Typedefs
Document your enums and function typedefs:
Generate Documentation
Build the documentation target:
This generates docs/index.yaml with all your function information.
Parse to JSON
Run the parser to convert YAML to the manifest format:
Or with filtering:
Use in Your Manifest
Copy the generated methods array from exported_methods.json into your plugin manifest:
Advanced: Enum Structures
The parser automatically includes complete enum definitions when a parameter uses an enum type:
Generated Output:
Advanced: Function Typedefs
Function pointer typedefs are automatically parsed into complete prototypes:
Generated Output:
Note: Function typedef parameter names are auto-generated as param1, param2, etc. You may want to customize these in the manifest for better documentation.
Best Practices
- Use
PLUGIN_API: Always use thePLUGIN_APImacro to mark functions for export. - Follow Type Conventions: Adhere to Plugify's type conventions for parameters and return values.
- Document Your Functions: Use Doxygen-style comments (
@brief,@param,@return) to document exported functions. - Automate When Possible: Use the clang-doc parser to automate manifest generation and reduce manual errors.
- Document Enums and Typedefs: Include Doxygen comments on enums and typedefs for complete manifest generation.
- Test Thoroughly: Test your exported functions to ensure they work as expected when called by other plugins.
- Keep Manifests Updated: If using manual manifests, ensure they stay synchronized with your code. If using automation, regenerate after changes.
Conclusion
Exporting functions in C++ plugins is straightforward when you follow Plugify's conventions and best practices. By using the PLUGIN_API macro, adhering to type conventions, and optionally automating manifest generation with clang-doc and the Python parser, you can create robust and interoperable plugins with minimal manual effort. For more advanced use cases, such as handling callbacks or working with enums, the automated parser provides complete type information including enum structures and function prototypes.