编译内核之后相应的文件会产生一个 .*.o.cmd的依赖文件, 根据此文件可以看出被编译的.o文件依赖哪些头文件,以及被编译的参数.
.o.cmd文件的格式为:
cmd_dir/output.o := commands
dep_dir/output.o := depended_files
总的来说由两部份组成, 一个是编译命令, 另一个是依赖文件. 所以此法分析分成两结: CMD_SECTION(命令) 和 DEP_SETION(依赖), 进入的条件分别是 cmd_... 和 dep_...
我们要提取出依赖的头文件, 所以CMD_SETION不做任何处理.
DEP_SETION 中分别由 $(wildcard include-file), include-file两部分组成, 而且都有续行符号"\".
这里遇到 include-file 后判断是否是.h文件以及不带解决路径的头文件, 如果是的话打印文件名到标准输出即可. (带绝对路径的是标准库头文件, 这里不需要).
编译命令: flex scan.l; gcc lex.yy.c
============================scan.l==============================================
%{
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int linenum = 1;
char file[2048];
%}
NAME ([[:alpha:]_][[:alnum:]_\-]*)
FILE_NAME [[:alnum:]_\-./]+
DEP_NAME (deps_{NAME}\/{NAME}\.o)
CMD_NAME (cmd_{NAME}\/{NAME}\.o)
NL \r?\n
WS [[:blank:]]+
OPTWS [[:blank:]]*
%x CMD_SECTION DEP_SETION
%%
int line_continue = 0;
<INITIAL>{
^{CMD_NAME} BEGIN(CMD_SECTION);
^{DEP_NAME} BEGIN(DEP_SETION);
{NL} linenum++;
. /* ignore spurious characters */
}
<CMD_SECTION>{
{NL} BEGIN(INITIAL); linenum++;
{OPTWS}":="
.
}
<DEP_SETION>{
{NL} {
if (!line_continue) {
// fprintf(stderr, "goto initial now at line %d\n", linenum);
BEGIN(INITIAL);
}
line_continue = 0;
linenum++;
}
\\$ line_continue = 1;//fprintf(stderr, "get continue line\n");
{OPTWS}":=" // fprintf(stderr, "get ==\n");
"$(wildcard " // fprintf(stderr, "get wildcard\n");
")" // fprintf(stderr, "get )\n");
{FILE_NAME} {
// fprintf(stderr, "get file %s\n", yytext);
strncpy(file, yytext, sizeof(file));
file[sizeof(file)-1] = '\0';
filter_inc_files(file);
}
. // fprintf(stderr, "text : '%s'\n", yytext);
}
%%
int filter_inc_files(const char *file)
{
int len;
if (file[0] == '/')
return 0;
len = strlen(file);
if (len < 3) return -1;
if (file[len-1]!='h' || file[len-2] != '.')
return -1;
/*
if (access(file, 0)) {
fprintf(stderr, "include file '%s' no exist\n", file);
return -1;
}
*/
printf("%s\n", file);
return 0;
}
int yywrap(void)
{
return 1;
}
int main(int argc, char **argv)
{
yylex();
return 0;
}