为嵌入式MCU工程建立完整的cscope和ctags索引

这几天深入了解了一下vim的神级插件YouCompleteMe,果然厉害,但是在MCU工程中函数跳转和语义补全就歇菜了,研究了几天也没找到很好的使用方法,最终还是无法在MCU嵌入式工程中跳转函数定义,这是无法忍受的,在PC或mac上的c/c++/clang工程可以完美使用。所以我还是老实的使用cscope和ctags吧,本篇文章就简单说一下,如何为MCU工程建立完整的索引,完成完美跳转!

MCU工程

现状

  • macOS平台
  • mcu为siliconlab的EFM32单片机,EFM32JG1B200
  • 编辑器vim

安装了Silicon Labs官方的开发环境simplicity studio为EFM32的开发带来很大的方便,是很棒的开发工具,同时可以很方便的管理SDK和toolchain,十里却希望可以用vim完成代码编写和阅读,为了实现向开发环境中的各种跳转,十里决定使用cscope和ctags。建立工程依旧使用Simplicity Studio,建立好的工程会生成相应的makefile,这就免去了自己写makefile的麻烦!

SDK和Toolchains目录

  • SDK
    • “/Applications/Simplicity Studio.app/Contents/Eclipse/developer/sdks/gecko_sdk_suite/v1.1/”
  • toolchain
    • “/Applications/Simplicity Studio.app/Contents/Eclipse/developer/toolchains/gnu_arm/4.9_2015q3”

思路

先用find命令查找源文件和头文件,并建立索引文件cscope.files,然后通过索引文件创建数据库,这里要注意的是生成的索引文件中,每行代表一个文件的路径,如果路径中包含空格cscope会无法识别正确路径,所以需要用sed命令添加双引号进行处理,而ctags读取索引文件时会自动添加双引号所以应该在sed处理索引文件前先建立ctags数据库。

上述过程可以shell脚本的方式实现。

shell脚本

最终脚本如下:

#!/bin/bash

list_sources() {
    echo "---> Listing sources..."
	
    find	"/Applications/Simplicity Studio.app/Contents/Eclipse/developer/toolchains/gnu_arm/4.9_2015q3/arm-none-eabi/include" 	\
			-path "/Applications/Simplicity Studio.app/Contents/Eclipse/developer/toolchains/gnu_arm/4.9_2015q3/arm-none-eabi/include/c++" -prune -o	\
        	-type f -name "*.[chsS]" -print > cscope.tmp

	find	"/Applications/Simplicity Studio.app/Contents/Eclipse/developer/sdks/gecko_sdk_suite/v1.1/platform/emlib/inc"			\
			"/Applications/Simplicity Studio.app/Contents/Eclipse/developer/sdks/gecko_sdk_suite/v1.1/platform/CMSIS/Include"		\
			"/Applications/Simplicity Studio.app/Contents/Eclipse/developer/sdks/gecko_sdk_suite/v1.1/platform/Device/SiliconLabs/EFM32JG1B/Include"	\
			"/Applications/Simplicity Studio.app/Contents/Eclipse/developer/sdks/gecko_sdk_suite/v1.1/hardware/kit/common/bsp"		\
			"/Applications/Simplicity Studio.app/Contents/Eclipse/developer/sdks/gecko_sdk_suite/v1.1/hardware/kit/common/drivers"	\
			"."	\
        	-type f -name "*.[chsS]" -print >> cscope.tmp
}

create_cscope_db() {
	#因为目录中包含空格,所以需要将生成的文件索引中每行文件路径放到双引号中
	sed 's/^/"/;s/$/"/' cscope.tmp > cscope.files

    echo "---> Creating cscope DB..."
    cscope -k -b -q -R -i cscope.files
}

create_ctags_db() {
    echo "---> Creating CTags DB..."
    ctags -L cscope.tmp
}

cleanup() {
    echo "---> Removing garbage..."
    rm -f cscope.files cscope.tmp
}

list_sources
# 因为ctags读取文件索引的时候会对每一行加上引号解决路径包含空格的问题,所以建立ctags库应该直接用加引号前的文件cscope.tmp
create_ctags_db
create_cscope_db
cleanup

结语

在相应的工程下运行这个脚本,就会建立完整文件的cscope和ctags索引,就可以happy地各种跳转了,包括SDK中的源码。

因为不可能就只用到EFM32这一个MCU平台,所以十里又写了一个脚本mktags,其还可以建立Renesas平台的工程索引,这里只加了这一个,其实可以参考十里写的脚本很容易添加其他平台的,十里将其置于/usr/local/bin目录下,重启终端后就可以为所欲为的构建MCU工程的cscope和ctags索引了。

mktags帮助信息如下:

Usage: /usr/local/bin/mktags SUB_COMMAND [MCU_NAME]
1. SUB_COMMAND:
    build: build the cscope database for MCU_NAME
    clean: no need MCU_NAME, clean the old cscope database
    help: no need MCU_NAME, show the help tips
    info: show the infomation of MCU_NAME
2. MCU_NAME:
    rx21a -> renesas RX mcu
    efm32jg -> Silicon labs efm32 mcu
Example:
    /usr/local/bin/mktags build efm32jg
    This can build cscope database at current dir for efm32jg