C工程自动注册子模块_框架重构--Apple的学习笔记

一,前言

之前已经用了跳表的框架C工程框架_学以致用--Apple的学习笔记,然后在example子系统中,添加一个个小的示例函数c文件,进行数据结构的复习。主要目的就是看了那么多源码,所以要学以致用,自己创建自己的轮子,便于将来使用。那么说到轮子,当然期望不断的优化咯。我喜欢同一件事用不同的方法去做。那么今天就修改下跳表法框架,模仿的是qemu源码中看到的hw注册机制type_init。

二,C工程新框架说明

只要每个example.c中调用EXAMPLE_REGISTER进行注册,那么就不需要每次在main的大数组中添加example函数供调用了。原理也是很简单的,就是每个子模块example.c代码注册到链表中,main函数循环扫描链表即可。
main.c变的更加简洁了,特别是对于多人共同开发的大型项目,这样的注册方式是便捷的。为了适配新框架,主要添加了utility文件夹及其内容。
文件结构如下:


image.png

main.c代码如下

/******************************************************************************
| Project                      : MiniC
| Description                  : MiniC project
| CPU and Compiler             : win10 CodeBlocks MinGw32
|               R E V I S I O N   H I S T O R Y
|-------------------------------------------------------------------------------
| Date        Version   Author     Description
| ----------  --------  ------     ---------------------------------------------
| 2020-04-23  01.00.00  AppleCai   First version
| 2020-04-26  01.00.00  AppleCai   Modify arch.Use auto register for adding examples
*******************************************************************************/
/*********************
 *      INCLUDES
 *********************/
#include 
#include 
#include "main.h"
/**********************
 *      MACROS
 **********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
*     GLOBAL VAR
**********************/

/**********************
 *     CONST VAR
 **********************/

/**********************
 * Functions Implement
 **********************/

int main()
{
    char cmd;
    boolean ret = 0;
    printf("**************************************************************\n");
    printf("****Welcome to miniC V1.0.0 project! Copyright by AppleCai****\n");
    printf("**************************************************************\n");
    module_print_info();
    printf("Please select test item[1-9],print q to exit,print h for help!Please:");
    moduleInit();
    while (scanf("%c",&cmd))
    {
        getchar(); //clear key \n
        if (cmd=='q')
        {
            printf("Bye Apple Cai!\n");
            break;
        }
        else if(cmd =='h')
        {
            module_print_info();
            printf("Please select test item[1-9],print q to exit,print h for help!Please:");
        }
        else
        {
            ret = module_call_init(cmd-0x30);
            if(ret)
            {
                printf("\nPlease select next test item[1-9],print q to exit,print h for help!Please:");
            }
            else
            {
                printf("\nPlease select a valid test item for 1 to 9,print q to exit,print h for help!Please:");
            }

        }
    }
    printf("Please press any key to exit the miniC project!");
    getchar();
    return 0;
}

现在的main函数收到命令后通过调用module_call_init来循环扫描链表,执行对应的命令函数。并且添加了help显示,提示供支持几条命令。
看完代码后,唯一一个问题大家要问的就是,main函数中不需要先调用下EXAMPLE_REGISTER函数吗?否则怎么注册进入的呢?

三,C语言技巧说明

以前看RT-theardOS或者linux驱动源码中,我记得也有类似驱动注册,然后do_init_call函数调用就会一个个执行对应的函数。而它的技巧是根据ld链接文件定义的了初始化段空间,利用了gcc特殊属性将函数依次排序放入初始化段空间,而do_init_call就通过指针依次扫描段空间的地址进行运行(每个函数名其实就是地址)。
而我今天是在win10上,没有链接文件,那么我是怎么实现的呢!
每个example子系统中的c代码只要调用EXAMPLE_REGISTER(slist,"slist1",1)就可以实现注册,然后看下EXAMPLE_REGISTER代表的内容吧~

#define EXAMPLE_REGISTER(pa1,pa2,pa3)  \
static void __attribute__((constructor)) do_minic_init_ ## pa1(void)    \
{                                                                           \
    moduleInit();                                                           \
    register_module_init(pa1,pa2,pa3);                                      \
}

看到了没,秘密就在这里__attribute__((constructor)),gcc这个constructor属性,可以让此函数do_minic_init_slist在main函数执行前就执行。那么虽然大家没有看到我在main函数中调用添加链表,原因是带constructor属性的函数会在main函数前自动运行。而关于module的注册,我用的就是之前自己做的仿linux双链表实现的module注册和遍历。

四,总结

学以致用,乐趣无穷,我喜欢对比,喜欢用不同的方式造轮子,折腾吧!说不定过段时间我又把框架改了,哈哈~

你可能感兴趣的:(C工程自动注册子模块_框架重构--Apple的学习笔记)