自动生成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

 

posted @ 2018-05-19 14:06  Five100Miles  阅读(606)  评论(0编辑  收藏  举报