Начните свой модуль, включив заголовочный файл emacs-module.h и определив символ совместимости GPL:
#include <emacs-module.h> int plugin_is_GPL_compatible;
Файл emacs-module.h устанавливается в дерево включений вашей системы в рамках установки Emacs. Альтернативно, вы можете найти его в исходном коде Emacs.
Далее напишите функцию инициализации для модуля.
int emacs_module_init (struct emacs_runtime *runtime) ¶Emacs вызывает эту функцию при загрузке модуля. Если модуль не экспортирует
функцию с именем emacs_module_init, попытка загрузки
модуля вызовет ошибку. Функция инициализации должна возвращать ноль, если
инициализация прошла успешно, и ненулевое значение в противном случае. В
последнем случае Emacs вызовет ошибку, и загрузка модуля завершится неудачей.
Если пользователь нажмет C-g во время инициализации,
Emacs игнорирует возвращаемое значение функции инициализации и завершает работу
(см. Завершение работы). (При необходимости
вы можете перехватить выход пользователя внутри функции инициализации, см.
should_quit.)
Аргумент runtime — это указатель на структуру C struct,
которая включает 2 публичных поля: size, которое предоставляет
размер структуры в байтах; и get_environment, которое
предоставляет указатель на функцию, позволяющую функции инициализации модуля
получать доступ к объекту окружения Emacs и его интерфейсам.
Функция инициализации должна выполнить любую необходимую инициализацию для модуля. Кроме того, она может выполнить следующие задачи:
Модуль может проверить, совместим ли исполняемый файл Emacs, который
загружает модуль, с самим модулем, сравнивая член size
структуры runtime с значением, скомпилированным в модуль:
int
emacs_module_init (struct emacs_runtime *runtime)
{
if (runtime->size < sizeof (*runtime))
return 1;
}
Если размер переданного объекту модуля объекта выполнения меньше, чем он ожидает, это означает, что модуль был скомпилирован для более новой версии Emacs (более поздней), чем та, которая пытается его загрузить, то есть модуль может быть несовместим с бинарным файлом Emacs.
Кроме того, модуль может проверить совместимость API
модуля с тем, что ожидает модуль. Следующий пример кода предполагает, что
он является частью функции emacs_module_init, показанной
выше:
emacs_env *env = runtime->get_environment (runtime);
if (env->size < sizeof (*env))
return 2;
Это вызывает функцию get_environment, используя указатель,
предоставленный в структуре runtime, чтобы получить указатель
на API environment, структуру C struct,
которая также имеет поле size, хранящее размер структуры в
байтах.
Наконец, вы можете написать модуль, который будет работать со старыми версиями Emacs, сравнивая размер окружения, переданного Emacs, с известными размерами, как это:
emacs_env *env = runtime->get_environment (runtime);
if (env->size >= sizeof (struct emacs_env_26))
emacs_version = 26; /* Emacs 26 или новее. */
else if (env->size >= sizeof (struct emacs_env_25))
emacs_version = 25;
else
return 2; /* Неизвестная или неподдерживаемая версия. */
Это работает потому, что более новые версии Emacs всегда добавляют члены к окружению, никогда не удаляя какие-либо члены, поэтому размер может только увеличиваться с выходом новых версий Emacs. Учитывая версию Emacs, модуль может использовать только те части API модуля, которые существовали в этой версии, поскольку эти части идентичны в более поздних версиях.
emacs-module.h определяет макрос препроцессора
EMACS_MAJOR_VERSION. Он раскрывается в целочисленный литерал, который
является последней основной версией Emacs, поддерживаемой заголовком.
См. Информация о версиях. Обратите
обратите внимание, что значение EMACS_MAJOR_VERSION является
константой времени компиляции и не представляет версию Emacs, которая в данный
момент запущена и загрузила ваш модуль. Если вы хотите, чтобы ваш модуль
был совместим с различными версиями emacs-module.h, а
также с различными версиями Emacs, вы можете использовать условную компиляцию
на основе EMACS_MAJOR_VERSION.
Мы рекомендуем, чтобы модули всегда выполняли проверку совместимости, если они не выполняют свою работу полностью в функции инициализации и не обращаются к каким-либо объектам Lisp или не используют какие-либо функции Emacs, доступные через структуру окружения.
Это дает функциям модуля имена, чтобы код Lisp мог вызывать их по этому имени. Мы описываем, как это сделать, в Написании функций модуля ниже.