自动生成cscope脚本
内核目录下可以使用make cscope快速生成对应架构的数据库, 仅这点就把渣渣si甩了一条街. 其实实现原理很简单, cscope是通过读取cscope.files中文件列表建立的数据库, 因此只要控制cscope.files的输入即可实现不同架构下建立的不同cscope.out.
我们先来看看内核是怎么做的. 主目录Makefile中cscope目标会调用scripts/tags.sh脚本, 后者根据传参会生成tags, cscope等, 我们就看下cscope.
1 docscope() 2 { 3 (echo \-k; echo \-q; all_target_sources) > cscope.files 4 cscope -b -f cscope.out 5 }
-k是使用kernel mode, 即不包含/usr/include的头文件.
-q是使用反转索引, 开启后会额外生成两个文件, 但可以加快索引效率.
-b是建立交叉引用.
-f是指定文件名.
以上选项均可以通过man cscope获取说明.
all_target_sources是关键, 它通过find命令将所需的源文件名输入cscope.files中. 这里有个地方没看懂记录下: $tree是怎么赋值成内核目录树的.
可以根据不同架构生成不同名字的cscope.out然后在需要时载入对应的cscope.out文件, 这样查看工程远比si等ide方便.
注意反汇编的文件不要以*.S命名, 否则被当做汇编加入数据库会导致cscope.out剧烈膨胀, 曾经一个工程生成上G的文件, 而内核的cscope.out才400M.
再补充下ctags的生成方式, 由于ctags命令较多, 因此比cscope稍微复杂一点. 首先ctags有两种版本, Exuberant版与Emacs版. 由于当前服务器使用Exuberant版, 就以前者为例, 内核目录下的tags.sh有对两种版本的不同处理.
因为ctags是根据字符串匹配原理来生成tag文件, 因此它不能很好的处理预处理宏, 对于内核或第三方库中使用的特殊宏需要我们手动修改它的定义. 说下tags.sh中用到的常用选项:
-a 以append方式将生成的tags添加到tag文件尾部.
-I 标识符列表, 一些属性宏(i.e. __attribute__)会影响ctags对函数/变量的判断, 需要将它们加入标识符列表中避免误判.
--regex-<language>=/regex/replace/kind-spec/flags <language>需要替换为对应的语言(i.e. asm c c++), regex与replace分别为要替换的正则表达式与替换后的字符串, kind-spec可不填(默认为r, regex), flags可选b(basic regex), e(extend regex, default), i(case-insensitive). 该选项可以将tags中宏名函数替换为真实名字函数(i.e. 以SYSCALL开头的系统调用被替换为sys开头的函数).
--extra=[+|-]flags flags可以为f或g.
--<language>-kinds=[+|-]kinds 没找到kinds的枚举, 只知道p(prototype), x(extern), d(macro).
小结: ctags是根据字符串匹配的, 因此不能很好的识别宏及c++的扩展. 但是它生成方便, 在没有ycm情况下做为临时索引还是很好用的. 另外同样不要包含反汇编的文件, 否则生成10G的tags也不是不可能.
1 #!/bin/sh 2 SH_DIR=$PWD/$(dirname $0) 3 TOP_DIR=$SH_DIR/../../../../ 4 PRODUCT_DIR=$TOP_DIR/product/ 5 src_dirs=$TOP_DIR/build/drv_pub/ 6 src_dirs+=\ $TOP_DIR/product/compile/ 7 src_dirs+=\ $TOP_DIR/product/drv_src/kernel_src/ 8 src_dirs+=\ $TOP_DIR/product/drv_src/usr_src/ 9 DEBUG_PATH= 10 if [ -n "$DEBUG_PATH" ]; then 11 touch test && chmod +x test && echo > test 12 PRINT_FILE="-fprint $SH_DIR/test" 13 else 14 PRINT_FILE="-print" 15 fi 16 find_c_sources() 17 { 18 find $src_dirs -name "*.[chS]" -a -not -regex ".*x86_sdk.*" -not -type l $PRINT_FILE 19 } 20 find_makefile() 21 { 22 find $src_dirs -name Makefile -not -type l $PRINT_FILE 23 find $src_dirs -name *.config -not -type l $PRINT_FILE 24 find $src_dirs -name *.mk -not -type l $PRINT_FILE 25 } 26 find_sources() 27 { 28 find_c_sources 29 find_makefile 30 } 31 make_ctags() 32 { 33 if [ -f tags ]; then 34 rm tags 35 fi 36 if ! ctags --version | grep -iq exuberant ; then 37 echo "ctags version mismatch!" 38 exit 1 39 fi 40 find_sources | xargs ctags -a -I --extra=+f --c-kinds=+px \ 41 --regex-c='/^#?[ \t]?CONFIG_([a-zA-Z0-9_]+)/\1/' 42 } 43 make_cscope() 44 { 45 if [ -f cscope.out ]; then 46 rm cscope.* 47 fi 48 (echo \-k; echo \-q; find_sources) > cscope.files 49 if [ ! -n "$DEBUG_PATH" ]; then 50 cscope -b -f cscope.out -i cscope.files 51 fi 52 } 53 target_check() 54 { 55 CHECK_BASE=$(basename -a $PWD) 56 if [ "$CHECK_BASE" != "product" ]; then 57 echo "wrong path!" 58 exit 1 59 fi 60 BUILD_LIST=$(cat $PWD/Makefile | \ 61 awk -F "\n" 'BEGIN{temp[2] = 0;} {match($1, /^(.+):$/, temp); print temp[1];}' 62 ) 63 for i in $BUILD_LIST; 64 do 65 if [ "$i" == "$1" ]; then 66 BUILD_TARGET=$i 67 break 68 fi 69 done 70 if [ "$BUILD_TARGET" == "" ]; then 71 echo "wrong target!" 72 exit 1 73 fi 74 BUILD_CLEAN=$(echo $BUILD_TARGET | sed -r 's/(.*)[_].+/\1_clean/') 75 echo $BUILD_CLEAN 76 CLEAN_FIND=0 77 for i in $BUILD_LIST; 78 do 79 if [ "$i" == "$BUILD_CLEAN" ]; then 80 CLEAN_FIND=1 81 break 82 fi 83 done 84 if [ $CLEAN_FIND -eq 0 ]; then 85 BUILD_CLEAN=clean 86 fi 87 88 echo "BUILD_TARGET is" $BUILD_TARGET 89 echo "BUILD_CLEAN is" $BUILD_CLEAN 90 } 91 make_check() 92 { 93 target_check $1 94 TYPE=$(cat $TOP_DIR/build/Compatible_Device_List | \ 95 awk -F "\n" 'BEGIN{temp[2] = 0;} {match($1, /^COMPATIBLE_DEVICE_LIST_([^=]+)=.*/, temp); print temp[1];}' 96 ) 97 for i in $TYPE; 98 do 99 FILE=./temp_build.$i 100 SKIP=$(echo $i | \ 101 awk 'BEGIN{temp[2] = 0;} {match($1, /V([0-9]+)R.+/, temp); if(temp[1] > 2){print $0;}else{print 1};}' 102 ) 103 if [ "$SKIP" == "1" ]; then 104 echo "board type" $i "too old to build. SKIP!" 105 continue 106 fi 107 echo "============================" 108 echo "Begin to make on board" $i 109 echo "log file on" $FILE 110 echo "============================" 111 make $BUILD_CLEAN DEVICE_TYPE=$i >> $FILE 2>&1 112 make $BUILD_TARGET DEVICE_TYPE=$i >> $FILE 2>&1 113 if [ $ -ne 0 ]; then 114 echo "*********************************************" 115 echo "End make" $i "with FAILUEEEEEEEEEEEEEEEE!!!" 116 echo "*********************************************" 117 break 118 else 119 echo "End make" $i "with SUCCESS" 120 rm $FILE 121 fi 122 done 123 } 124 usage() 125 { 126 echo "usage:" 127 echo "$0 ctags" 128 echo "$0 cscope" 129 echo "$0 check [target]" 130 echo "$0 sdk" 131 } 132 if [ $# -eq 0 ]; then 133 usage; 134 else 135 case "$1" in 136 "ctags") 137 make_ctags 138 ;; 139 "cscope") 140 cd $TOP_DIR 141 make_cscope 142 ;; 143 "check") 144 cd $PRODUCT_DIR 145 make_check $2 146 ;; 147 "sdk") 148 make_sdk 149 ;; 150 esac 151 fi