2013-06-26 58 views
2

我有一个简单的命令行界面在我的AVR微控制器固件,根据各地的结构是这样的:CLI命令表GCC

typedef struct { 
    const char *name; 
    const char *usage; 
    const char *help; 
    void (*handler)(char **last); 
} command_t; 

extern command_t *cli_commands[]; 

我希望能在声明中不同模块的命令尽可能干。到目前为止,我有这样我定义我的功能是这样的:

COMMAND_IMPL(replay, "replay <n>", "Replay frame n") { 
    // 'last' argument is for strtok_t 
} 

,然后我必须有这个在我.c文件之一:

COMMAND_DECL(list); 
COMMAND_DECL(clear); 
COMMAND_DECL(replay); 

COMMAND_TABLE 
    COMMAND(list) 
    COMMAND(clear) 
    COMMAND(replay) 
END_COMMAND_TABLE 

我的宏是这样的:

#define COMMAND_IMPL(name, usage, help) \ 
    static void cli_handle_##name##_command(char **);\ 
    command_t cli_##name##_command = {#name, usage, help, cli_handle_##name##_command};\ 
    static void cli_handle_##name##_command(char **last) 
#define COMMAND_DECL(name) extern command_t cli_##name##_command; 
#define COMMAND_TABLE command_t *cli_commands[] = { 
#define COMMAND(name) ((command_t *) &cli_##name##_command), 
#define END_COMMAND_TABLE NULL }; 

可以做得比这更好吗?这个项目已经与avr-gcc绑定了,所以我不介意它是否是GCC专用的解决方案。链接器功能的解决方案也可以(我正在编译为ELF)。我在想,也许我可以将命令条目放在不同的部分,并将其链接到已知的某个地方,但我不知道它会如何终止。

回答

1

您可以使用section属性像这样(这是Linux内核是如何导出它的功能):

#define COMMAND_IMPL(name, usage, help) \ 
    static void cli_handle_##name##_command(char **); \ 
    command_t cli_##name##_command __attribute((section("commands"))) = { #name, usage, help, cli_handle_##name##_command }; \ 
static void cli_handle_##name##_command(char **last) 

然后,你可以使用一个ld脚本(参见http://www.math.utah.edu/docs/info/ld_3.html)获得的地址开始所述 '命令' 部分的/端:

... 
SECTION commands ALIGN(4) : { 
    commands_begin = .; 
    *(commands) 
    commands_end = .; 
} 

最后,声明两个变量:

extern command_t commands_begin, commands_end;

然后,您可以使用这些变量的地址,以获得指挥结构的整个列表,即

for (command_t *cmd = &commands_begin; cmd != &commands_end; cmd++) 
    ... 

注意如何&commands_end点只是超出了最后的命令。

+1

请注意,您不需要此链接器脚本。海湾合作委员会将使2个符号可用于您的部分。您可以简单地声明'extern command_t * __ start_commands;'和'extern command_t * __ stop_commands;'来获取指向创建的“commands”部分的开头和结尾的指针。 – nos

+0

如何控制该部分进入哪个部分?我需要它进入文本段(我认为 - 这是AVR pgmspace数据)。 – Derecho

+0

我从ld得到这个错误: /opt/local/lib/gcc/avr/4.7.2/../../../../avr/bin/ld:在[000000000000175a加载的部分cli_cmdtable, 0000000000001771] overlapped section .data loaded at [000000000000175a,000000000000193b] – Derecho