Прототип анализатора команд модуля 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 ответа:
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 ответ, как они помогли мне и еще одному добровольцу решить проблему для нашего проекта.