ctags使用详解

一.         ctags 是干什么的

ctags 的功能:扫描指定的源文件,找出其中所包含的语法元素,并将找到的相关内容记录下来。

我用的是 Exuberant Ctags ,在 Windows 上使用,就一个可执行文件,非常绿色,可在 sourceforge 下载。

二.         ctags 可以识别哪些语言,是如何识别的

ctags 识别很多语言,可以用如下命令来查看:

ctags --list-languages

还可以识别自定义语言,具体没研究过。

    ctags 是可以根据文件的扩展名以及文件名的形式来确定该文件中是何种语言,从而使用正确的分析 器。可以使用如下命令来查看默认哪些扩展名对应哪些语言:

ctags --list-maps

还可以指定 ctags 用特定语言的分析器来分析某种扩展名的文件或者名字符合特定模式的文件。例如如下命令告 知 ctags ,以 inl 为扩展名的文件是 c++ 文件。

ctags --langmap=c++:+.inl –R

    并不十分清楚 ctags 使用何种技术来解析内容,估计包括正则表达式、词法分析、语法分析等等。但 ctags 不是编译器也不是预处理器,它的解析能力是有限的。例如它虽然可以识别宏定义,但对于使 用了宏的语句的识别还是有缺陷的,在一些稍微正规点的代码(例如 ACE 的库或 VC 的头文件等)中的某些常规的宏使用方式会导致 ctags 无法识别,或者识别错误,从而使得 ctags 没有记录 user 想记录的内容,或者记录下的信息不准确。另一方面 ctags 也有聪明的一面,例如在 cpp 文件中扫描到 static 的全局变量时, ctags 会记录这个变量,而且还会标明说这个变量是局限于本文件的,同样的定义,如果放在 h 文件中, ctags 则不会标明说这个变量是局限于本文件的,因为 ctags 认为 h 文件是头文件的一种,会被其他文件 include ,所以在其他文件中可能会用到该 h 文件里定义的这个全局变量。

三.         ctags 可以识别和记录哪些语法元素

可以用如下命令查看 ctags 可以识别的语法元素:

ctags --list-kinds

或者单独查看可以识别的 c++ 的语法元素

ctags --list-kinds=c++

    ctags 识别很多元素,但未必全都记录,例如“函数声明”这一语法元素默认是不记录的,可以控制 ctags 记录的语法元素的种类。如下命令要求 ctags 记录 c++ 文件中的函数声明和各种外部和前向声明:

ctags -R --c++-kinds=+px

四.         ctags 是怎么记录的

不管一次扫描多少文件,一条 ctags 命令把记录的内容都记到一个文件里去,默认是当前目录的 tags 文件,当然这是可以更改的。

每个语法元素对应文件里的一行, 学名叫 tag entry 

1)              开头是 tag 的名字,其实也就是语法元素的名字,例如记录的是函数的话则 tag 名就是函数名,记录的是类的话, tag 名就是类名。

2)              接下来是一个 tab 

3)              接下来是语法元素所 在的文件名。

4)              又是一个 tab 

5)              一条“命令”。这个 要解释一下意义: ctags 所记录的内容的一个功能就是要帮助像 vi 这样的编辑器快速定位到语法元素所在的文件中去。前面已经记录了语法元素所在的文件,这 条命令的功能就是一旦在 vi 中打开语法元素所在的文件,并且执行了该“命令”后, vi 的光标就能定位到语法元素在文件中的具体位置。所以该“命令”的内容一般分两种,一种是 一个正则表达式的搜索命令,一种是第几行的指向命令。默认让 ctags 在记录时自行选择命令的种类,选择的依据不详,可以通过命令行参数来强制 ctags 使用某种命令,这里就不多谈了。

6)              对于本 tag entry (简称 tag )所对应的语法元素的描述,例如语法元素的类型等。具体内容和语法元素的种类密切相关。 显示哪些描述,显示的格式等都是可以在命令行指定的。例如如下命令要求描述信息中要包含: a 表示如果语法元素的类的成员的话,要标明其 access (即是 public 的还是 private 的); i 表示如果有继承,标明父类; K 表示显示语法元素的类型的全称; S 表示如果是函数,标明函数的 signature  z 表示在显示语法元素的类型是使用 kind:type 的格式。

ctags -R --fields=+aiKSz

    ctags 除了记录上述的各种内容之外,还可以在 tags 文件中记录本次扫描的各个文件,一个文件名对应一个 tag entry 。默认是不记录的,要强制记录要是使用如下命令:

ctags –R --extra=+f

    还可以强制要求 ctags 做这样一件事情——如果某个语法元素是类的一个成员,当然 ctags 默认会给其记录一个 tag entry (说白了就是在 tags 文件里写一行),可以要求 ctags 对同一个语法元素再记一行。举一个例子来说明:假设语法元素是一个成员函数, ctags 默认记录的 tag entry 中的 tag 的名字就是该函数的名字(不包括类名作为前缀),而我们强制要求 ctags 多记的那个 tag entry  tag 的名字是包含了类明作为前缀的函数的全路径名。这样做有什么好处见下文分析。强制 ctags给类的成员函数多记一行的命令为:

ctags -R --extra=+q

五.         vi 大概是怎样使用 ctags 生成的 tags 文件的

估计 vi 是这样使用 tags 文件的:我们使用 vi 来定位某个 tag 时, vi 根据我们输入的 tag 的名字在 tags 文件中一行行查找,判断每一行 tag entry  tag 名字(即每行的开头)是否和用户给出的相同,如果相同就认为找到一条记录,最后 vi 显示所有找到的记录,或者根据这些记录直接跳转到对应文件的特定位置。

考虑到 ctags 记录的内容和方式,出现同名的 tag entry 是很常见的现象,例如函数声明和函数定义的 tag 名字是一样的,重载函数的 tag 名字是一样的等等。 vi只是使用 tag 名字来搜索,还没智能到可以根据函数的 signature 来选择相应的 tag entry  vi 只能简单的显示 tag entry 的内容给 user ,让 user 自行选择。

ctags 在记录成员函数时默认是把函数的名字(仅仅是函数的名字,不带任何类名和 namespace 作为前缀)作为 tag 的名字的,这样就导致很多不同类但同名的函数所对应的 tag entry 的名字都是一样的,这样 user  vi 中使用函数名来定位时就会出现暴多选择,挑选起来十分麻烦。 user 可能会想在 vi 中用函数的全路径名来进行定位,但这样做会失败,因为 tags 文件中没有对应名字的 tag entry 。要满足用户的这种心思,就要求 ctags 在记录时针对类的成员多记录一条 tag entry ,该 tag entry 和已有的 tag entry 的内容都相同,除了 tag 的名字不同,该 tag entry 的名字是类的成员的全路径名(包括了命名空间和类名)。这就解释了 ctags  --extra=+q 这样一条命令行选项(见四)。

六.         我的一条 ctags 命令

ctags -R --languages=c++ --langmap=c++:+.inl -h +.inl --c++-kinds=+px --fields=+aiKSz --extra=+q --exclude=lex.yy.cc --exclude=copy_lex.yy.cc

命令太长了,折成两行了,可以考虑把命令的各个参数写到文件里去了(具体做法就不谈了)。

1.

-R

表示扫描当前目录及所有子目录(递归向下)中的源文件。并不是所有文件 ctags 都会扫描,如果用户没有特别指明,则 ctags 根据文件的扩展名来决定是否要扫描该文件——如果 ctags 可以根据文件的扩展名可以判断出该文件所使用的语言,则 ctags 会扫描该文件。

2.

--languages=c++

只扫描文件内容判定为 c++ 的文件——即 ctags 观察文件扩展名,如果扩展名对应 c++ ,则扫描该文件。反之如果某个文件叫 aaa.py  python 文件),则该文件不会被扫描。

3.

--langmap=c++:+.inl

告知 ctags ,以 inl 为扩展名的文件是 c++ 语言写的,在加之上述 2 中的选项,即要求 ctags  c++ 语法扫描以 inl 为扩展名的文件。

4.

-h +.inl

告知 ctags ,把以 inl 为扩展名的文件看作是头文件的一种( inl 文件中放的是 inline 函数的定义,本来就是为了被 include 的)。这样 ctags 在扫描 inl 文件时,就算里面有 static 的全局变量, ctags 在记录时也不会标明说该变量是局限于本文件的(见第一节描述)。

5.

--c++-kinds=+px

记录类型为函数声明和前向声明的语法元素(见第三节)。

6.

--fields=+aiKSz

控制记录的内容(见第四节)。

7.

--extra=+q

 ctags 额外记录一些东西(见第四、五节)。

8.

--exclude=lex.yy.cc --exclude=copy_lex.yy.cc

告知 ctags 不要扫描名字是这样的文件。还可以控制 ctags 不要扫描指定目录,这里就不细说了。

七.         本文内容来源

    Exuberant Ctags 附带的帮助文档( ctags.html )。

限时福利1:原价 129 元,最后2天仅需 69 元!后天涨价至98元 限时福利2:购课进答疑群专享柳峰(刘运强)老师答疑服务 限时福利3:购课添加助教领取价值 800 元的编程大礼包 为什么需要掌握高性能的MySQL实战? 由于互联网产品用户量大、高并发请求场景多,因此对MySQL的性能、可用性、扩展性都提出了很高的要求。使用MySQL解决大量数据以及高并发请求已经是程序员的必备技能,也是衡量一个程序员能力和薪资的标准之一。 为了让大家快速系统了解高性能MySQL核心知识全貌,我为你总结了「高性能 MySQL 知识框架图」,帮你梳理学习重点,建议收藏! 【课程设计】 课程分为四大篇章,将为你建立完整的 MySQL 知识体系,同时将重点讲解 MySQL 底层运行原理、数据库的性能调优、高并发、海量业务处理、面试解析等。 一、性能优化篇: 主要包括经典 MySQL 问题剖析、索引底层原理和事务与锁机制。通过深入理解 MySQL 的索引结构 B+Tree ,学员能够从根本上弄懂为什么有些 SQL 走索引、有些不走索引,从而彻底掌握索引的使用和优化技巧,能够避开很多实战中遇到的“坑”。 二、MySQL 8.0新特性篇: 主要包括窗口函数和通用表表达式。企业中的许多报表统计需求,如果不采用窗口函数,用普通的 SQL 语句是很难实现的。 三、高性能架构篇: 主要包括主从复制和读写分离。在企业的生产环境中,很少采用单台MySQL节点的情况,因为一旦单个节点发生故障,整个系统都不可用,后果往往不堪设想,因此掌握高可用架构的实现是非常有必要的。 四、面试篇: 程序员获得工作的第一步,就是高效的准备面试,面试篇主要从知识点回顾总结的角度出发,结合程序员面试高频MySQL问题精讲精练,帮助程序员吊打面试官,获得心仪的工作机会。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页