本文是受到这篇文章的启发: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文件里包含的头文件,那么就可以获得我们需要的所有内核源码了!!!
以下是具体操作步骤:
- 把打印信息保存到log里,这里以pcduino nano3举例,其他开发板类似
对于已经编译过的内核源码,可以使用make distclean重新来过。 - 把getKernelSourceCode这个bin文件拷贝到内核源码根目录,然后输入以下指令,
./getKernelSourceCode arm sunxi build_log.txt file_lists.txt - 把生成的file_lists.txt导出到windows下
- 打开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;
}
四 结语
如果有写的不对或不好的地方,希望能留言指正,谢谢阅读。