针对大型c项目的跳转定义思考

不知道大佬们有没有做嵌入式类型工作的,一个的嵌入式项目包含uboot,kernel,rootfs,各种库,各种应用,这样的项目代码量应该相当于几十个kernel吧。

在这样的项目里面想实现查找、跳转定义,emacs 目前的体验很难做到 source insight那样的效果。

lsp肯定不行,

ctags 的话,光生成 TAGS 就要 10G 以上的空间,而且生成的时间也很长。

然后就是 dumb-jump ,dumb-jump使用rg来搜索,速度还是太慢了。目前我宁愿使用 color-rg 等这样的插件 搜索后,自己去找 函数定义。不知道 大佬们 是用什么模式工作的?

现在我有个想法就是 类似 dumb-jump 的工作,就是 使用 rg 搜索后,在用 tree-sitter 来找到 函数定义,最后显示在一个buffer里面,不知道 这样的方案怎么样?

1 个赞

没有相关工作经验,但对 ctags 很熟,强答一下 :rofl:

通过一些技巧可以把内核的 tags 文件减到 500M 以下:

$ pwd
/yard/code/linux-5.17.9
$ ctags -n --languages=C,C++,KConfig,Asm,LdScript --extras=-{fileScope} -f .tags -R
$ du -BM .tags
449M	.tags

这里的关键有二:

  1. -n 选项可以不生成 search pattern 而用行号代替,能节省不少空间。
  2. --extras=-{fileScope} 可以不生成具有 file scope(也就是从外面不能引用)的符号的 tag。

如果您不需要看某些文件夹的代码的话,可以把它们排除掉。比如排除 foo 文件夹:

--exclude=foo/*

不知道这个大小对您的工程可以接受吗 :rofl:

然后就是不要用 Emacs 的 TAGS 格式,TAGS 格式不能做二分搜索,查定义很慢。可以用我的 Citre,支持 ctags 原本的 tags 格式,速度很快。

2 个赞

感谢大佬的Citre,其实我很早就使用过。

首先 你这里是一个kernel 就 500M,我们一个项目相当于 几十个kernel,就是 5G以上了,可想而知 生成和更新速度 应该在 10分钟了,就算 5分钟 也难受了。

我也想 如果是把一个大项目 拆分 为几个小项目,这就涉及到 不同 tags 的切换了,也挺复杂的。

用slickedit试试看,不过这么巨大的代码量,tags式的代码分析性能和准确度都不会太好,也不看好slickedit,没用slickedit试过.

我也一直想支持多个 tags 文件,但没有想到好的做法 :rofl:

虽然项目很大, 但通常个人需要关注的文件不会特别多吧… 可以考虑只给这些文件生成 tags.

我能想到的是分成多个tags,因为切换tags文件要重新加载,为了节省重新加载时间,可以打开多个emacs进程,不同的emacs进程加载不同的tags文件。

可以单独对子项目使用lsp/tags呀. 这些子项目一般都是独立存在的啊, 比如kernel, bootloader. 比如你kernel一般又引用outoftree的代码. 为啥要一起生成索引呢.

1 个赞

实际开发的时候,比如一个大点的应用,除了 应用本身的代码外,可能还依赖了某些库。

单独 生成tags 肯定不现实,一个项目起码要生成几十个 tags,看代码的时候还会各种跳转。 所以如果不是做这方面工作的,可能不会理解吧。

2 个赞

那你生成一个tag更不现实啊, 比如sdk里面如果包含个4,5个不同版本的kernel, 然后tag索引的时候岂不是就乱套了, 同时蹦出来多个候选, 太麻烦了. 另外, 你说十几个kernel, 我很好奇你的应用到底是啥应用. 我至今只看到qt的代码比linux kernel还多…

git clone --depth=1 GitHub - torvalds/linux: Linux kernel source tree 后的代码数量分析如下:

% cloc linux
   75817 text files.
   64949 unique files.
   10872 files ignored.

github.com/AlDanial/cloc v 1.92  T=243.15 s (267.1 files/s, 128914.4 lines/s)
---------------------------------------------------------------------------------------
Language                             files          blank        comment           code
---------------------------------------------------------------------------------------
C                                    31177        3153478        2509739       16145073
C/C++ Header                         22490         636311        1197771        5888167
reStructuredText                      3112         152103          61073         416445
Assembly                              1287          46320          98593         224469
YAML                                  2542          45499          11683         205704
JSON                                   374              2              0         193519
Bourne Shell                           814          24438          16588          95324
make                                  2714          10291          11505          47135
SVG                                     63             81           1162          39654
Perl                                    66           7362           5024          36439
Python                                 141           6100           5792          30437
yacc                                     9            698            409           4912
PO File                                  5            791            918           3077
lex                                      9            346            309           2108
C++                                     10            372            138           2016
Bourne Again Shell                      50            296            251           1304
awk                                     11            155            126           1111
Glade                                    1             58              0            603
NAnt script                              2            153              0            589
CSV                                      7             73              0            544
Cucumber                                 1             30             50            183
TeX                                      1              6             73            147
TNSDL                                    2             33              0            140
Clojure                                 46              7              0            138
Windows Module Definition                2             15              0            109
m4                                       1             15              1             95
CSS                                      2             35             37             90
XSLT                                     5             13             26             61
Umka                                     1             16              0             34
vim script                               1              3             12             27
Ruby                                     1              4              0             25
INI                                      1              1              0              6
sed                                      1              2              5              5
---------------------------------------------------------------------------------------
SUM:                                 64949        4085107        3921285       23339690
---------------------------------------------------------------------------------------

先说一下我的工作内容:日常主要做虚拟化开发,也会遇到需要同时操作多个 repo 代码的场景 (KVM, QEMU, 多个不同的 Linux Kernel Tree, EDK2/OVMF, SPDK, DPDK 等),但是只有个别 repo 需要频繁修改 (KVM + QEMU),其它 repo 以读为主。

我在代码浏览跳转的方面解决方法非常简单粗暴,就是空间换时间:

  • 大硬盘 (1TB) + 大内存 (64GB)
  • 每个 repo 单独开一个 emacs (不是 emacsclient),
  • 用 cscope + xcscope 做各种查找跳转 (caller/definition/reference 之类的)
  • 对于比较大的 repo,例如 kernel 这类的,会在构建初始的 cscope db 时把大机率用不到的文件都过滤掉 (比如大量的 driver 和 fs 代码)

基本只有第一次构建 db 时会比较慢,类似 kernel 这类的大概要 1 ~ 2 分钟左右,构建完的 db 大概在 1 ~ 2 GB 左右;后续代码修改引入的变化,基本上都是靠 cscope 和 xcscope 做增量更新,增量更新基本无感,大概秒级吧。

代码查找方面,基本只有第一次 cscope 查找会有点慢,kernel 这类比较大的大概会有十秒左右的延迟;之后的查找就比较块了,基本就是秒级吧。

1 个赞

C++用cscope效果不错,我一直想写个使用cscope代码导航插件,可以使用一些现代的ui.但是不确定还有多少人用cscope,

cscope 好像是个解决方案,我先试试来。你所说的体验 跟 source insight 很像。

图片 图片

source insight 刚开始创建这些工程 也是会花一些时间,后面跳转就流畅了。

感觉cscope 有点意思,就我们这种行业来讲,好像用source insight还很多,我向他们推荐 emacs 的时候,他们最看重的一个功能 就是 函数定义跳转,

其他功能 emacs 都可以实现,当然有些肯定还比 source insight 更好用。

而且 source insight 还是收费软件, linux 下支持还不好,如果把 函数定义跳转 功能做好, emacs 基本可以 直接 替换 source insight了,

我查看nginx的代码时用gnu global + ggtags

我之前使用 ctag 在我的工程下面创建 tags 文件 用了 10分钟搞了 5G以上的tags 文件。

不知道 ggtag 会怎么样,但 感觉 比 ctag 还大一些,ggtag 功能更多一些。

但是我刚使用 cscope 用了 2-3分钟 创建了 1G多点的 cscope 文件,第一次搜索用了 30s,后面搜索就1s,感觉很不错。

也许cscope 比 ctag 功能少一些,但是目前提供的功能来讲足够了。

从以前使用的经验看,cscope对于C++的支持更好些。不过想问下,目前基于lsp的方案都不能满足项目要求吗?clangd,ccls之类的

然后就是 dumb-jump ,dumb-jump使用rg来搜索,速度还是太慢了。目前我宁愿使用 color-rg 等这样的插件 搜索后,自己去找 函数定义。不知道 大佬们 是用什么模式工作的?

理论上,dumb-jump 和color-rg 都是使用rg,效率不会差太多。我的项目中使用还是挺不错的

一直没好好的在c/c++ 中使用过 lsp,我看又得手动创建 compile_commands.json 之类的project文件,感觉不是很方便 。

global用的是gtags,gtags在代码变化后可以动态更新gtags生成的文件。ggtags是emacs的package,可以从mepla安装。

好久没看c的代码了,所以没怎么用ggtags。