Прототип анализатора команд модуля Apache


Я создаю модуль Apache2 и испытываю странную проблему компиляции. Это прототип моей функции, используемой для разбора команды config с именем " analytics_ip":

static const char *apr_cfg_set_analytics_ip(cmd_parms *cmd, void *config, const char *data);

Это массив структур command_rec , содержащих указатели на эту функцию:

static const command_rec apr_cmds[] =
{
 AP_INIT_TAKE1("analytics_ip", apr_cfg_set_analytics_ip, NULL, OR_ALL, ""),
 { NULL }
};

Структура command_rec объявлена в заголовочном файле http_config.h

typedef struct command_struct command_rec;
struct command_struct {
    /** Name of this command */
    const char *name;
    /** The function to be called when this directive is parsed */
    cmd_func func;
    /** Extra data, for functions which implement multiple commands... */
    void *cmd_data;
    /** What overrides need to be allowed to enable this command. */
    int req_override;
    /** What the command expects as arguments */
    enum cmd_how args_how;

    /** 'usage' message, in case of syntax errors */
    const char *errmsg;
};

Когда я следую cmd_func , он получает следующее объявление:

typedef const char *(*cmd_func) ();

Если это не так ошибочно, это означает "указатель на функцию, возвращающую указатель на символ и не принимающую никаких аргументов". Как это может быть возможно? Функция разбора команд должна принимать по крайней мере один параметр, содержащий модульное значение переменной config, соответствующей этой функции.

Я использую g++ для компиляции этого модуля. Сообщение об ошибке:

mod_xxx.h:65:2: error: invalid conversion from ‘const char* (*)(cmd_parms*, void*, const char*) {aka const char* (*)(cmd_parms_struct*, void*, const char*)}’ to ‘cmd_func {aka const char* (*)()}’ [-fpermissive]
  };

Заранее спасибо

2 3

2 ответа:

cmd_func это объединение, оно определено в http_config.h следующим образом:

typedef union {
    /** function to call for a no-args */
    const char *(*no_args) (cmd_parms *parms, void *mconfig);
    /** function to call for a raw-args */
    const char *(*raw_args) (cmd_parms *parms, void *mconfig,
                             const char *args);
    /** function to call for a argv/argc */
    const char *(*take_argv) (cmd_parms *parms, void *mconfig,
                             int argc, char *const argv[]);
    /** function to call for a take1 */
    const char *(*take1) (cmd_parms *parms, void *mconfig, const char *w);
    /** function to call for a take2 */
    const char *(*take2) (cmd_parms *parms, void *mconfig, const char *w,
                          const char *w2);
    /** function to call for a take3 */
    const char *(*take3) (cmd_parms *parms, void *mconfig, const char *w,
                          const char *w2, const char *w3);
    /** function to call for a flag */
    const char *(*flag) (cmd_parms *parms, void *mconfig, int on);
} cmd_func;

enum cmd_how args_how; отвечает за выбор правильной версии функции.

Коммутатор, обрабатывающий его, находится в server/config.c (в функции invoke_cmd).

Вы, кажется, используете версию "take1", которая соответствует cmd->AP_TAKE1 или просто cmd->take1.

Проблема может заключаться в том, что C и C++ имеютразличия относительно инициализации объединения . (AP_INIT_TAKE1 использует синтаксис { .take1=func }, который не работает в C++).

Вам придется инициализировать static const command_rec apr_cmds совместимым с C++способом или переместить его в отдельный объектный файл, скомпилированный с помощью C. Или, если вы не используете C++, просто скомпилируйте с помощью gcc.

Для проекта, над которым я работаю, мы добавили приведение, чтобы компиляция завершилась успешно, и код, кажется, работает нормально, поскольку он правильно читает значения, указанные в файле конфигурации. Вот выдержка из этой практики: extern "C" { static const command_rec kiwix_settings[] = { AP_INIT_TAKE1("zimFile", (const char* (*)())kiwix_set_zimfilename, NULL, RSRC_CONF, "The ZIM filename in full including the extension"), AP_INIT_TAKE1("zimPath", (const char* (*)())kiwix_set_path, NULL, RSRC_CONF, "The path to the ZIM file, including the trailing //"), { NULL } }; }

Полный файл (и действительно проект) являются opensourced. Вот ссылка на полный файл https://github.com/kiwix/kiwix-apache/blob/master/mod_kiwix.cpp

PS: спасибо за ваш вопрос и https://stackoverflow.com/users/257568/artemgr ответ, как они помогли мне и еще одному добровольцу решить проблему для нашего проекта.