Writing Language Module
Guide for extending Plugify with new languages.
This guide will walk you through the process of creating your first language module for the Plugify system. A language module allows Plugify to support plugins written in a specific programming language. By following this guide, you'll learn how to define a configuration file, implement the required interface, and integrate your module with the Plugify core.
Quick Start
Introduction
A language module in Plugify is a dynamic library that provides support for a specific programming language. Each language module must include a configuration file named .pmodule
, which contains metadata and settings required by the Plugify core to load and manage the module.
The Module Manifest
The .pmodule
file is a JSON configuration file that defines essential information about your language module. Below is an example of a .pmodule
file:
Explanation of Configuration Options
fileVersion
: The version of the configuration file format.version
: The semantic version of the language module.friendlyName
: A user-friendly name for the language module.language
: The programming language supported by the module (e.g., "cpp" for C++).description
: A brief description of the module's functionality.createdBy
: The author or organization that created the module.createdByURL
: A URL linking to the creator's profile or website.docsURL
: A URL to the module's documentation.downloadURL
: The URL for downloading the module (e.g., a ZIP file).updateURL
: The URL for checking and fetching updates.supportedPlatforms
: A list of platforms supported by the module (e.g., Windows, Linux).forceLoad
: Iftrue
, the module will be forcibly loaded by the Plugify core.
Implementing the ILanguageModule Interface
The ILanguageModule
interface defines the methods that your language module must implement. Below is an overview of the interface:
Key Methods
Initialize
: Called when the module is loaded. Use this to set up your module.Shutdown
: Called when the module is unloaded. Use this to clean up resources.OnUpdate
: Called when the module is updated. Use this for periodic updates.OnPluginLoad
: Called when a plugin is loaded. Use this to initialize the plugin.OnPluginStart
: Called when a plugin is started.OnPluginUpdate
: Called when a plugin is updated.OnPluginEnd
: Called when a plugin is ended.OnMethodExport
: Called when a plugin exports methods for inter-plugin communication.IsDebugBuild
: Returnstrue
if the module is built in debug mode.
Steps to Create Your First Language Module
Set Up Your Development Environment
Ensure you have the following tools installed:
- A text editor or IDE (e.g., Visual Studio, CLion).
- A compatible C++ compiler (e.g., MSVC, GCC, Clang).
- The Plugify framework installed and configured.
Use the Template Project
To simplify the process, clone the template-lang-module repository:
Configure and Build the Template
- Navigate to the project directory:
- Generate build files:
- Build the project:
Define Your Module's Functionality
- Implement the
ILanguageModule
interface in your module. - Add logic to load, manage, and execute plugins in your target language.
- Use the
plugify-function
library to dynamically generate C functions if needed.
Implement Marshaling Functionality (if needed)
For languages that require type conversion, implement marshaling wrappers to convert Plugify types (e.g., plg::vector
, plg::string
) to native types.
Create the Module Manifest
The .pmodule
file is a JSON configuration file that defines essential information about your language module. The template project already includes a .pmodule
file, so you only need to modify it to suit your module.
Key Fields to Update
language
: Specify the programming language that your module supports (e.g.,cpp
,python
,javascript
).friendlyName
: Provide a user-friendly name for your module.description
: Add a brief description of your module's functionality.downloadURL
: Update this field to point to the URL where your module's ZIP archive will be hosted.
Example of Manifest File
Here’s an example of a .pmodule
file for a C++ language module:
How to Modify the Template
- Open the
.pmodule
file in your template project. - Update the
language
field to specify the programming language your module supports. - Modify the
friendlyName
,description
, and other fields as needed. - Ensure the
downloadURL
points to the location where your module's ZIP archive will be hosted.
Package Your Module
Package your module files and the .pmodule
file into a ZIP archive. Update the downloadURL
in your .pmodule
file to point to this archive.
File Structure for the ZIP Archive
The ZIP archive for the package manager should contain the following files in this structure:
- bin/
- template_language_module.dll
- libtemplate_language_module.so
- template_language_module.pplugin
bin/
: This directory should contain the compiled binaries for your language module (e.g.,.dll
for Windows and.so
for Linux).template_language_module.pplugin
: This is the plugin manifest file that describes your language module.
Test Your Module
To properly test your language module, you need to create a cross_call_worker and use it together with the cross_call_master to verify that all functions are marshaled correctly. This ensures that your module can handle inter-plugin communication and data exchange.
Testing with Cross-Plugin Communication
- Create a cross_call_worker: Implement a plugin that exports methods to be called by the
cross_call_master
. This plugin should handle data exchange and method calls. - Use the cross_call_master: The
cross_call_master
will call methods from yourcross_call_worker
and verify that the data is correctly marshaled and processed. - Check the C++ Example: For a working example, refer to the
cpp-language-module
repository, which includes a fully implementedcross_call_worker
andcross_call_master
for testing.
Example Workflow
- The
cross_call_master
calls a method from thecross_call_worker
to pass a string. - The
cross_call_worker
processes the string and calls a method back on thecross_call_master
to return a modified string. - Verify that the string is correctly passed and returned.
Publish Your Module
Upload your module package to a hosting service (e.g., GitHub Releases) and share it with the Plugify community. To streamline the release process, you can use GitHub Actions to automatically create releases, generate repository JSON files, and handle platform-specific builds.
Using GitHub Actions for Releases
Our team has implemented GitHub Actions workflows in existing language modules (e.g., cpp-language-module
) to automate the release process. These workflows can serve as a good example for setting up your own automated release pipeline.
Key Features of the Workflow
- Automatic Releases:
- When a new tag is pushed (e.g.,
v1.0.0
), the workflow automatically creates a GitHub release. - The release includes the compiled module files and the
.pmodule
manifest.
- When a new tag is pushed (e.g.,
- Repository JSON Generation:
- The workflow generates a repository JSON file (e.g.,
plugify-module-cpp.json
) that contains metadata about the release. - This file is used by the Plugify package manager to check for updates.
- The workflow generates a repository JSON file (e.g.,
- Platform-Specific Builds:
- The workflow builds the module for multiple platforms (e.g., Windows, Linux) and includes the platform-specific binaries in the release.
- Checksum Verification:
- The workflow calculates checksums for the release artifacts to ensure file integrity.
- GitHub Pages Deployment:
- The repository JSON file is deployed to GitHub Pages, making it accessible to the Plugify package manager.
- Discord Notifications:
- The workflow sends a notification to a Discord channel when a new release is published.
Example Workflow
Here’s an example of a GitHub Actions workflow for automating releases:
How to Use
- Copy the workflow file (e.g.,
.github/workflows/release.yml
) from one of our existing language modules (e.g.,cpp-language-module
). - Modify the workflow to match your module's build process and file structure.
- Push the workflow file to your repository and create a new tag (e.g.,
v1.0.0
) to trigger the release process.
By using GitHub Actions, you can automate the release process and ensure that your module is always up-to-date and easily accessible to users.
Maintain and Update Your Module
- Update the
version
, and other fields in your.pmodule
file for each release. - Ensure the
updateURL
points to the latest.json
file for automatic updates.
Best Practices
- Keep Dependencies Minimal: Avoid unnecessary dependencies to ensure compatibility and performance.
- Use Debug Builds for Testing: Test your module in debug mode to catch issues early.
- Document Your Module: Provide clear documentation for users and developers.
- Follow Semantic Versioning: Use semantic versioning (e.g.,
1.0.0
) for your module releases.
Troubleshooting
- Module Not Loading: Ensure the
.pmodule
file is correctly formatted and placed in the right directory. - Plugins Failing to Initialize: Check the logs for errors and verify that your module implements all required methods.
- Debugging Tips: Use verbose logging and a debugger to identify and fix issues.