Создание языкового модуля

Руководство по расширению Plugify новыми языками.

Это руководство проведет вас через процесс создания вашего первого языкового модуля для системы Plugify. Языковой модуль позволяет Plugify поддерживать плагины, написанные на определенном языке программирования. Следуя этому руководству, вы научитесь определять файл конфигурации, реализовывать необходимый интерфейс и интегрировать ваш модуль с ядром Plugify.

Быстрый старт

Клонируйте шаблонный проект:

git clone https://github.com/untrustedmodders/template-lang-module.git

Соберите проект:

mkdir build && cd build
cmake --preset Debug
cmake --build .

Реализуйте интерфейс ILanguageModule.

Введение

Языковой модуль в Plugify — это динамическая библиотека, которая обеспечивает поддержку определенного языка программирования. Каждый языковой модуль должен включать файл конфигурации с именем .pmodule, который содержит метаданные и настройки, необходимые ядру Plugify для загрузки и управления модулем.

Манифест модуля

Файл .pmodule — это файл конфигурации в формате JSON, который определяет основную информацию о вашем языковом модуле. Ниже приведен пример файла .pmodule:

*.pmodule
{
    "fileVersion": 1,
    "version": "1.0.0",
    "friendlyName": "Языковой модуль C++",
    "language": "cpp",
    "description": "Добавляет поддержку плагинов на C++",
    "createdBy": "untrustedmodders",
    "createdByURL": "https://github.com/untrustedmodders/",
    "docsURL": "https://github.com/untrustedmodders/cpp-lang-module/README.md",
    "downloadURL": "https://github.com/untrustedmodders/cpp-lang-module/releases/download/v1.0/cpp-lang-module.zip",
    "updateURL": "https://raw.githubusercontent.com/untrustedmodders/cpp-lang-module/main/cpp-lang-module.json",
    "supportedPlatforms": [],
    "forceLoad": false
}

Объяснение опций конфигурации

  • fileVersion: Версия формата файла конфигурации.
  • version: Семантическая версия языкового модуля.
  • friendlyName: Удобное для пользователя имя языкового модуля.
  • language: Язык программирования, поддерживаемый модулем (например, "cpp" для C++).
  • description: Краткое описание функциональности модуля.
  • createdBy: Автор или организация, создавшая модуль.
  • createdByURL: URL-адрес, ссылающийся на профиль или веб-сайт создателя.
  • docsURL: URL-адрес документации модуля.
  • downloadURL: URL-адрес для загрузки модуля (например, ZIP-файл).
  • updateURL: URL-адрес для проверки и получения обновлений.
  • supportedPlatforms: Список платформ, поддерживаемых модулем (например, Windows, Linux).
  • forceLoad: Если true, модуль будет принудительно загружен ядром Plugify.

Реализация интерфейса ILanguageModule

Интерфейс ILanguageModule определяет методы, которые должен реализовать ваш языковой модуль. Ниже приведен обзор интерфейса:

plugin.cpp
namespace plugify {
    class ILanguageModule {
    protected:
    ~ILanguageModule() = default;

    public:
        virtual InitResult Initialize(std::weak_ptr<IPlugifyProvider> provider, ModuleHandle module) = 0;
        virtual void Shutdown() = 0;
        virtual void OnUpdate(DateTime dt) = 0;
        virtual LoadResult OnPluginLoad(PluginHandle plugin) = 0;
        virtual void OnPluginStart(PluginHandle plugin) = 0;
        virtual void OnPluginUpdate(PluginHandle plugin, DateTime dt) = 0;
        virtual void OnPluginEnd(PluginHandle plugin) = 0;
        virtual void OnMethodExport(PluginHandle plugin) = 0;
        virtual bool IsDebugBuild() = 0;
    };
}

Ключевые методы

  • Initialize: Вызывается при загрузке модуля. Используйте для настройки вашего модуля.
  • Shutdown: Вызывается при выгрузке модуля. Используйте для очистки ресурсов.
  • OnUpdate: Вызывается при обновлении модуля. Используйте для периодических обновлений.
  • OnPluginLoad: Вызывается при загрузке плагина. Используйте для инициализации плагина.
  • OnPluginStart: Вызывается при запуске плагина.
  • OnPluginUpdate: Вызывается при обновлении плагина.
  • OnPluginEnd: Вызывается при завершении работы плагина.
  • OnMethodExport: Вызывается, когда плагин экспортирует методы для межплагинного взаимодействия.
  • IsDebugBuild: Возвращает true, если модуль собран в режиме отладки.

Шаги по созданию вашего первого языкового модуля

Настройте вашу среду разработки

Убедитесь, что у вас установлены следующие инструменты:

  • Текстовый редактор или IDE (например, Visual Studio, CLion).
  • Совместимый компилятор C++ (например, MSVC, GCC, Clang).
  • Установленный и настроенный фреймворк Plugify.

Используйте шаблонный проект

Чтобы упростить процесс, клонируйте репозиторий template-lang-module:

git clone https://github.com/untrustedmodders/template-lang-module.git

Настройте и соберите шаблон

  1. Перейдите в каталог проекта:
    cd template-lang-module
    
  2. Сгенерируйте файлы сборки:
    mkdir build && cd build
    cmake --preset Debug
    
  3. Соберите проект:
    cmake --build .
    

Определите функциональность вашего модуля

  • Реализуйте интерфейс ILanguageModule в вашем модуле.
  • Добавьте логику для загрузки, управления и выполнения плагинов на вашем целевом языке.
  • Используйте библиотеку plugify-function для динамической генерации функций C, если это необходимо.

Реализуйте функциональность маршалинга (при необходимости)

Для языков, требующих преобразования типов, реализуйте обертки для маршалинга, чтобы преобразовывать типы Plugify (например, plg::vector, plg::string) в нативные типы.

Создайте манифест модуля

Файл .pmodule — это файл конфигурации в формате JSON, который определяет основную информацию о вашем языковом модуле. Шаблонный проект уже включает файл .pmodule, поэтому вам нужно только изменить его в соответствии с вашим модулем.

Ключевые поля для обновления

  • language: Укажите язык программирования, который поддерживает ваш модуль (например, cpp, python, javascript).
  • friendlyName: Укажите удобное для пользователя имя вашего модуля.
  • description: Добавьте краткое описание функциональности вашего модуля.
  • downloadURL: Обновите это поле, чтобы оно указывало на URL, где будет размещен ZIP-архив вашего модуля.

Пример файла манифеста

Вот пример файла .pmodule для языкового модуля C++:

*.pmodule
{
    "fileVersion": 1,
    "version": "1.0.0",
    "friendlyName": "Языковой модуль C++",
    "language": "cpp",
    "description": "Добавляет поддержку плагинов на C++",
    "createdBy": "untrustedmodders",
    "createdByURL": "https://github.com/untrustedmodders/",
    "docsURL": "https://github.com/untrustedmodders/cpp-lang-module/README.md",
    "downloadURL": "https://github.com/untrustedmodders/cpp-lang-module/releases/download/v1.0/cpp-lang-module.zip",
    "updateURL": "https://raw.githubusercontent.com/untrustedmodders/cpp-lang-module/main/cpp-lang-module.json",
    "supportedPlatforms": [],
    "forceLoad": false
}

Как изменить шаблон

  1. Откройте файл .pmodule в вашем шаблонном проекте.
  2. Обновите поле language, чтобы указать язык программирования, который поддерживает ваш модуль.
  3. Измените поля friendlyName, description и другие по мере необходимости.
  4. Убедитесь, что downloadURL указывает на место, где будет размещен ZIP-архив вашего модуля.

Упакуйте ваш модуль

Упакуйте файлы вашего модуля и файл .pmodule в ZIP-архив. Обновите downloadURL в вашем файле .pmodule, чтобы он указывал на этот архив.

Структура файлов для ZIP-архива

ZIP-архив для менеджера пакетов должен содержать следующие файлы в этой структуре:

  • bin/
    • template_language_module.dll
    • libtemplate_language_module.so
  • template_language_module.pplugin
  • bin/: Этот каталог должен содержать скомпилированные бинарные файлы вашего языкового модуля (например, .dll для Windows и .so для Linux).
  • template_language_module.pplugin: Это файл манифеста плагина, который описывает ваш языковой модуль.

Протестируйте ваш модуль

Чтобы правильно протестировать ваш языковой модуль, вам необходимо создать cross_call_worker и использовать его вместе с cross_call_master для проверки правильности маршалинга всех функций. Это гарантирует, что ваш модуль может обрабатывать межплагинное взаимодействие и обмен данными.

Тестирование с межплагинным взаимодействием

  1. Создайте cross_call_worker: Реализуйте плагин, который экспортирует методы для вызова из cross_call_master. Этот плагин должен обрабатывать обмен данными и вызовы методов.
  2. Используйте cross_call_master: cross_call_master будет вызывать методы из вашего cross_call_worker и проверять, что данные правильно маршалируются и обрабатываются.
  3. Проверьте пример на C++: Для рабочего примера обратитесь к репозиторию cpp-language-module, который включает полностью реализованные cross_call_worker и cross_call_master для тестирования.

Пример рабочего процесса

  1. cross_call_master вызывает метод из cross_call_worker для передачи строки.
  2. cross_call_worker обрабатывает строку и вызывает метод обратно в cross_call_master, чтобы вернуть измененную строку.
  3. Убедитесь, что строка была правильно передана и возвращена.

Опубликуйте ваш модуль

Загрузите пакет вашего модуля на хостинг (например, GitHub Releases) и поделитесь им с сообществом Plugify. Чтобы упростить процесс выпуска, вы можете использовать GitHub Actions для автоматического создания релизов, генерации JSON-файлов репозитория и обработки сборок для конкретных платформ.

Использование GitHub Actions для релизов

Наша команда реализовала рабочие процессы GitHub Actions в существующих языковых модулях (например, cpp-language-module) для автоматизации процесса выпуска. Эти рабочие процессы могут служить хорошим примером для настройки вашего собственного автоматизированного конвейера выпуска.

Ключевые особенности рабочего процесса
  1. Автоматические релизы:
    • При пуше нового тега (например, v1.0.0) рабочий процесс автоматически создает релиз на GitHub.
    • Релиз включает скомпилированные файлы модуля и манифест .pmodule.
  2. Генерация JSON репозитория:
    • Рабочий процесс генерирует JSON-файл репозитория (например, plugify-module-cpp.json), который содержит метаданные о релизе.
    • Этот файл используется менеджером пакетов Plugify для проверки обновлений.
  3. Сборки для конкретных платформ:
    • Рабочий процесс собирает модуль для нескольких платформ (например, Windows, Linux) и включает специфичные для платформы бинарные файлы в релиз.
  4. Проверка контрольных сумм:
    • Рабочий процесс вычисляет контрольные суммы для артефактов релиза для обеспечения целостности файлов.
  5. Развертывание на GitHub Pages:
    • JSON-файл репозитория развертывается на GitHub Pages, делая его доступным для менеджера пакетов Plugify.
  6. Уведомления в Discord:
    • Рабочий процесс отправляет уведомление в канал Discord при публикации нового релиза.
Пример рабочего процесса

Вот пример рабочего процесса GitHub Actions для автоматизации релизов:

Как использовать
  1. Скопируйте файл рабочего процесса (например, .github/workflows/release.yml) из одного из наших существующих языковых модулей (например, cpp-language-module).
  2. Измените рабочий процесс в соответствии с процессом сборки и структурой файлов вашего модуля.
  3. Отправьте файл рабочего процесса в ваш репозиторий и создайте новый тег (например, v1.0.0), чтобы запустить процесс выпуска.

Используя GitHub Actions, вы можете автоматизировать процесс выпуска и гарантировать, что ваш модуль всегда будет актуальным и легко доступным для пользователей.

Поддерживайте и обновляйте ваш модуль

  • Обновляйте version и другие поля в вашем файле .pmodule для каждого релиза.
  • Убедитесь, что updateURL указывает на последний файл .json для автоматических обновлений.

Рекомендации

  • Минимизируйте зависимости: Избегайте ненужных зависимостей для обеспечения совместимости и производительности.
  • Используйте отладочные сборки для тестирования: Тестируйте ваш модуль в режиме отладки, чтобы выявлять проблемы на ранней стадии.
  • Документируйте ваш модуль: Предоставляйте четкую документацию для пользователей и разработчиков.
  • Следуйте семантическому версионированию: Используйте семантическое версионирование (например, 1.0.0) для релизов вашего модуля.

Устранение неполадок

  • Модуль не загружается: Убедитесь, что файл .pmodule правильно отформатирован и размещен в правильном каталоге.
  • Плагины не инициализируются: Проверьте логи на наличие ошибок и убедитесь, что ваш модуль реализует все необходимые методы.
  • Советы по отладке: Используйте подробное логирование и отладчик для выявления и устранения проблем.