本文是受到这篇文章的启发:http://www.cnblogs.com/mouou/p/4599148.html
该作者使用shell编程,运行起来会比较耗时,所以这里使用C++按照作者思路重新编写一遍,提高效率,并修复了一些小bug。


一 问题由来

linux内核源码比较庞大,在导入到source insight时会非常耗时,而且导入后查看代码时也会遇到诸多问题,如函数的重复定义,软件崩溃等。而做嵌入式开发,往往只需要用到与具体硬件相关的代码就可以了。那么如何从内核源码里提取到我们需要的代码呢?


二 具体操作

在编译内核源码前,一般要先指定好architecture和machine,例如pcduino nano3,其architecture是arm,machine是sunxi,我们在配置内核时会输入
make ARCH=arm sunxi_defconfig
然后再进行编译,编译过程会打印很多信息,如下,
这里写图片描述
其中的每个.o文件对应一个.c文件,这个.c文件就是我们需要的文件。

只要把编译时打印的信息保存到log里,然后通过分析log来提取所有.c文件以及.c文件里包含的头文件,那么就可以获得我们需要的所有内核源码了!!!

以下是具体操作步骤:

  1. 把打印信息保存到log里,这里以pcduino nano3举例,其他开发板类似
    这里写图片描述
    对于已经编译过的内核源码,可以使用make distclean重新来过。
  2. 把getKernelSourceCode这个bin文件拷贝到内核源码根目录,然后输入以下指令,
    ./getKernelSourceCode arm sunxi build_log.txt file_lists.txt
  3. 把生成的file_lists.txt导出到windows下
  4. 打开source insight,新建工程到如下步骤时,选择Add from list…
    这里写图片描述
    然后再弹出的对话框中选择file_lists.txt,这样就可以了,
    这里写图片描述
    后面在source insight里进行同步会很快,文件也只有3000个左右。这样再去阅读内核源码就会很方便了。

三 C++源码

用到了正则表达式,所以编译时需要通过-std=c++11来开启c++11特性,
g++ -std=c++11 getKernelSourceCode.cpp -o getKernelSourceCode
具体源码如下所示(给变量起名字太难了),

#include <unistd.h>

#include <cstdio>
#include <fstream>
#include <set>
#include <string>
#include <regex>

using namespace std;


regex re_1("^\\s*CC\\s*(.*)");
regex re_2("^.*#include\\s*<(([^/]*)/.*)>"); 
regex re_3("^.*#include\\s*\"(.*)\"");
regex re_4("(^.*/)[^/]+\\.c");
regex re_5("^.*\\s+(.*\\.h)");

bool saveSourceFileToSet(const string& logFile, set<string>& sSavedSrcFile);
void printStringSet(const set<string>& targetSet);
bool saveSetToFile(const set<string>& targetSet, const string& fileName);
bool fileExisted(const string& oneFileName);
bool findIncludes(const string& oneSrcFile, set<string>& container);
bool getRawFile_1(const smatch& match, string& rawFile);
string getPrefix(const string& srcFile);
bool getRawFile_2(const smatch& match, string& rawFile, const string& srcFile);

string strArchName = "arm";
string strMachName = "sunxi";

set<string> KeyWords = 
{
    "acpi", "asm-generic", "clocksource", "config", "crypto",
    "drm", "dt-bindings","generated", "keys", "linux", "math-emu", "media", "misc",
    "mtd", "net", "pcmcia", "rdma", "rxrpc", "scsi", "sound", "target",
    "trace", "uapi", "video", "xen"
};


int main(int argc, char* argv[])
{
    if (argc < 5) 
    {
        printf("usage: %s arch machine input output\n", argv[0]);
        return 1;
    }

    set<string> setSrcFile;
    set<string> setTotalFiles;

    strArchName = argv[1];
    strMachName = argv[2];

    saveSourceFileToSet(argv[3], setSrcFile);
    setTotalFiles = setSrcFile;

    set<string>::const_iterator it = setSrcFile.begin();
    for (; it != setSrcFile.end(); ++it)
    {
        if (findIncludes((*it), setTotalFiles) == false)
        {
            break;
        }

    }

    saveSetToFile(setTotalFiles, argv[4]);

    return 0;
}



bool findIncludes(const string& oneSrcFile, set<string>& container)
{
    ifstream in(oneSrcFile);
    if (!in)
    {
        fprintf(stderr, "Error: open %s fail.\n", oneSrcFile.c_str());
        return false;
    }


    string oneline, rawFile;
    smatch results;

    while (getline(in, oneline))
    {
        regex_search(oneline, results, re_2); // <XX>

        if (getRawFile_1(results, rawFile))
        {
            if (container.find(rawFile) == container.end()) // new file
            {
                
                container.insert(rawFile);
                findIncludes(rawFile, container);
            }
        }
        else
        {
            regex_search(oneline, results, re_3); // "XX"
            if (getRawFile_2(results, rawFile, oneline))
            {
                if (container.find(rawFile) == container.end()) // new file
                {
                    container.insert(rawFile);
                    findIncludes(rawFile, container);
                }
                
            }
        }
    }

    in.close();

    return true;
}


string getPrefix(const string& srcFile)
{
    smatch match;
    regex_search(srcFile, match, re_4);
    if (match.empty() == false)
    {
        return match.str(1); 
    }

    return "";
}


// if @rawFile exist and @match is not empty, return true
bool getRawFile_2(const smatch& match, string& rawFile, const string& srcFile)
{

    if (match.empty() == false)
    {
        string pre = getPrefix(srcFile);
        rawFile = pre + match.str(1);
        if (fileExisted(rawFile))
            return true;
    }

    return false;
}


// if @rawFile exist and @match is not empty, return true
bool getRawFile_1(const smatch& match, string& rawFile)
{
    string prefixFolder;

    if (match.empty() == false)
    {
        if (match.size() == 3)
        {
            prefixFolder = match.str(2);

            if (KeyWords.find(prefixFolder) != KeyWords.end())
            {
                rawFile = "include/" + match.str(1);
                if (fileExisted(rawFile))
                    return true;
                else
                {
                    if (prefixFolder == "linux")
                    {
                        rawFile = "include/uapi/" + match.str(1);
                        if (fileExisted(rawFile))
                            return true;
                    }
                }
            }
            else
            {
                if (prefixFolder == "asm")
                {
                    rawFile = "arch/" + strArchName + "/include/" + match.str(1);
                }
                else if (prefixFolder == "mach")
                {
                    rawFile = "arch/" + strArchName + "/mach-" + strMachName + "/include/" + match.str(1);
                }

                if (fileExisted(rawFile))
                    return true;
            }
        }

    }

    return false;
}


bool saveSourceFileToSet(const string& logFile, set<string>& sSavedSrcFile)
{
    ifstream in(logFile);

    if (!in)
    {
        fprintf(stderr, "Error: open %s fail.\n", logFile.c_str());
        return false;
    }

    string oneline, rawFile;
    smatch results;

    string::size_type pos = 0;

    while (getline(in, oneline))
    {
        regex_search(oneline, results, re_1);
        if (results.empty() == false)
        {
            rawFile = results.str(1);
            if (fileExisted(rawFile) == false)
                continue;

            pos = rawFile.find(".o");
            if (pos != string::npos) 
                sSavedSrcFile.insert(rawFile.substr(0, pos) + ".c");
            else
                sSavedSrcFile.insert(results.str(1));
        }
        else
        {
            regex_search(oneline, results, re_5);
            rawFile = results.str(1);
            if (fileExisted(rawFile) == false)
                continue;

            sSavedSrcFile.insert(rawFile);

        }
    }


    in.close();

    return true;
}


void printStringSet(const set<string>& targetSet)
{
    set<string>::const_iterator it = targetSet.begin();
    for (; it != targetSet.end(); ++it)
    {
        printf("%s\n", (*it).c_str());
    }

    printf("\n");;
}

bool saveSetToFile(const set<string>& targetSet, const string& fileName)
{
    ofstream out(fileName);
    if (!out)
    {
        printf("Error: cannot open/create %s\n", fileName.c_str());
        return false;
    }

    set<string>::const_iterator it = targetSet.cbegin();

    for (; it != targetSet.cend(); ++it)
        out << (*it) << "\r\n";

    out.close();

    return true;
}

bool fileExisted(const string& oneFileName)
{
    if (access(oneFileName.c_str(), F_OK) == 0)
        return true;
    else
        return false;
}

四 结语

如果有写的不对或不好的地方,希望能留言指正,谢谢阅读。

Logo

更多推荐