You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Asterisk自定义模块set_stats符号未定义问题求助

问题:调用自定义Asterisk模块函数触发未定义符号错误

我编写了一个名为Reset Queue Statistics的Asterisk自定义模块,模块本身可正常加载并按配置每分钟输出日志,但在app_queue.c中调用模块内的set_stats函数时,加载app_queue.so时报错:

Error loading module 'app_queue.so': /usr/lib/asterisk/modules/app_queue.so: undefined symbol: set_stats

自定义模块代码(res_resetqueuestats.c)

#include <time.h>
#include "asterisk/module.h"
#include "asterisk/logger.h"
#include "asterisk/res_resetqueuestats.h"

static unsigned int interval = 1;

int set_stats(const char *queuename){
    ast_log(LOG_NOTICE, "SET STATS CALLED FOR %s", queuename);
    return 0;
}

static void write_log(void)
{
   time_t now = time(NULL);
   struct tm *tm_now = localtime(&now);
   ast_log(LOG_NOTICE, "Current time interval: %02d:%02d\n", tm_now->tm_hour, tm_now->tm_min);
}

static void* log_thread(void* data)
{
  while (1) {
    time_t now = time(NULL);
    struct tm *tm_now = localtime(&now);
    if (tm_now->tm_min % interval == 0) {
        write_log();
    }
       usleep(60 * 1000 * 1000);
   }
 return NULL;
}

static int load_module(void)
{
   ast_log(LOG_NOTICE, "Loading Reset Queue Statistics module.\n");

   pthread_t thread;
   if (pthread_create(&thread, NULL, log_thread, NULL) != 0) {
      ast_log(LOG_ERROR, "Failed to create log thread.\n");
      return AST_MODULE_LOAD_FAILURE;
   }
  return AST_MODULE_LOAD_SUCCESS;
}

static int unload_module(void)
{
   ast_log(LOG_NOTICE, "Unloading Reset Queue Statistics module.\n");
   return 0;
}

AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Reset Queue Statistics");

对应头文件(res_resetqueuestats.h)

#define _RES_RESETQUEUESTATS_H

#include <asterisk.h>
#include <time.h>
#include "asterisk/module.h"
#include "asterisk/logger.h"

int set_stats(const char *queuename);

#endif

app_queue.c中的调用位置

// ... 其他头文件引入 ...
#include "asterisk/res_resetqueuestats.h"
//...
static void handle_hangup(void *userdata, struct stasis_subscription *sub,
        struct stasis_message *msg)
{
    // ... 原有业务代码省略 ...
    
    // 自定义函数调用
    int result = set_stats(queue_data->queue->name);
    remove_stasis_subscriptions(queue_data);
}

原因分析
  1. 动态模块独立加载特性:Asterisk的模块都是独立的动态链接库(.so),app_queue.so和你的自定义模块res_resetqueuestats.so属于两个完全独立的动态库,编译和加载阶段没有建立链接关系,因此app_queue.so无法找到set_stats的符号。
  2. 符号可见性限制:即使头文件声明了set_stats,但自定义模块编译时默认不会将该符号导出到全局符号表,其他模块无法直接访问。

解决方法

方法一:将自定义模块改为Asterisk内置静态模块(最直接)

  1. 将res_resetqueuestats.c和头文件移动到Asterisk源码的res/目录下。
  2. 修改Asterisk根目录的Makefile,将res_resetqueuestats.c添加到RES_SOURCES列表中。
  3. 重新编译Asterisk,此时自定义模块会被编译进核心程序,app_queue作为内置模块可直接调用set_stats函数。

方法二:修改编译规则,让app_queue链接到自定义模块

  1. 在自定义模块的编译规则中添加-fPIC参数,确保符号可导出(可在模块对应的Makefile中配置)。
  2. 修改apps/Makefile,在app_queue.so的编译链接参数中添加-lresetqueuestats,让其链接到你的自定义模块。
  3. 注意:这种方法需要保证自定义模块先于app_queue加载,否则仍会出现符号找不到的问题。

方法三:使用Asterisk规范的模块间交互机制(推荐)

Asterisk不推荐跨模块直接调用函数,建议通过以下规范方式实现:

  1. 注册模块服务:在自定义模块中注册一个服务,将set_stats作为服务接口暴露:
    // 自定义模块中添加服务定义
    typedef struct {
        int (*reset_stats)(const char *queuename);
    } reset_queue_stats_api;
    
    static reset_queue_stats_api api = {
        .reset_stats = set_stats,
    };
    
    static int load_module(void)
    {
        // ... 原有代码 ...
        ast_module_register_api("res_resetqueuestats", &api);
        return AST_MODULE_LOAD_SUCCESS;
    }
    
    static int unload_module(void)
    {
        // ... 原有代码 ...
        ast_module_unregister_api("res_resetqueuestats");
        return 0;
    }
    
  2. 在app_queue中调用服务:
    static void handle_hangup(void *userdata, struct stasis_subscription *sub,
            struct stasis_message *msg)
    {
        // ... 原有代码 ...
        reset_queue_stats_api *api = ast_module_get_api("res_resetqueuestats");
        if (api) {
            api->reset_stats(queue_data->queue->name);
        }
        // ... 原有代码 ...
    }
    

这种方式符合Asterisk的模块设计规范,避免了直接依赖问题,同时支持模块动态加载卸载。


内容的提问来源于stack exchange,提问作者Flamur Dervishi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 12:07:09