在非linux(Mac)上使用lsp-mode/lsp-bridge索引linux下c/c++代码

如题,目前身边同事是直接用vscode,ssh远程到远端机器,甚至是远端开发容器内,然后写代码。不得不佩服,vscode在这方面做的是真好。但我还是想用emacs来写代码,因为vscode定制性和快捷键与emacs差太远了。

目前我遇到的问题有以下几点:

  1. 项目是老旧的Makefile代码,对应的linux环境还是很老的版本,g++只有4.4.6,无法生成compile_commands.json文件,因为老到连bear都装不上。对此我采用的办法是在不同的工程目录下使用 .clangd文件,类似:
CompileFlags:
  Add: [-std=c++0x, -Wall, --target=x86_64-pc-linux-gnu, -Wno-reserved-user-defined-literal,
  -nobuiltininc,
  -nostdinc++,
  -nostdinc,
  -cxx-isystem/Users/byhc/work/env/linux_inc/c++,
  -stdlib++-isystem/Users/byhc/work/env/linux_inc/c++,
  -isystem/Users/byhc/work/env/linux_inc,
  -isystem/Users/byhc/work/imdep_common/usr/include,

  -D_POSIX_C_SOURCE=201103L,
  -D_XOPEN_SOURCE=600,
  -DBYTE_ORDER=1,
  ]
  Remove: [-arch]
  Compiler: /Users/byhc/.nix-profile/bin/clang++

这样做问题是需要在不同目录下放置 .clangd 文件,因为emacs下lsp有一个常见问题就是如果用 find-definition 之类的方法,从 /path/a/a.cpp 跳到 /path/b/b.cpp 后,b.cpp的分析就需要一个单独的 .clangd 了。

  1. Mac下头文件缺失,比如缺少 epoll.h 这样的文件,对此我的解决办法是在 .clangd 中包含 -nobuiltininc, -nostdinc++, -nostdinc, 三个编译选项,这样clang就不会去包含mac自己的头文件搜索路径,然后再指定包含我自己写的一套 linux_inc 头文件。 这样做坏处是得自己写全套的linux c/c++头文件。

想知道各位道友有没有遇到过类似问题,是怎样解决的?我自觉自己方法虽然有用,但过于麻烦,想看下有没有更好的使用姿势。

不用emacs + lsp/lsp-bridge做远程,是因为速度响应原因,无论是保存文件还是打开文件、切换buffer,都有较大延迟,此外tramp与本地的一些插件似乎也有兼容问题。

lsp-bridge远程开发没有性能问题,不受tramp影响

https://x.com/SnowAFK/status/1813638146581795108

这里不是说lsp-bridge有性能问题,是emacs整体在远程开发响应上就不是很好,比如用ivy框架时,如果打开远程文件,补全窗口会跳出来3次才能打开一个文件,然后如果要切换文件,switch-buffer或dired也需要较长时间打开。

另外即使是远程,也存在我上面说的,旧的linux下生成compile_commands.json是比较困难的,还得写.clangd。

你emacs版本多少的?

29.4,最新版了

1 个赞

确实卡,可以x11出来用x410

lsp-bridge用的是 buffer diff sync 同步的技术, 补全性能和 VSCode 一样。

其实文件管理器和打开文件都可以用类似 lsp-bridge 一样的技术, 先不要全部下载完再打开, 做成流式的, 这样速度就会很快。

可惜我日常远程开发的少, 其实做一个流式的文件管理器和远程文件打开功能, 就全部和VSCode一样快了。

只要有可能,都不想远程开发,因为无论怎样做,速度和响应方面都不如本地。所以我这里想讨论的是,在本地,mac上索引linux上的c/c++代码,有没有什么更好的办法和实践。

1 个赞

在其他环境生成 compile_commands.json 然后复制到此电脑如何。

较高版本的linux无法编译过现在的项目,那个makefile是十多年前的人写的了,除非重新梳理一遍依赖,并改造成cmake项目。

另外就是linux下生成的compile_commands.json,mac上也用不了,有些头文件是没有的。

这个思路之前我试过,弄到一半放弃了,有时间我再折腾下看能不能走通。

这种属于交叉编译了,最好还是在有环境的机器上开发吧。搞个远程协议开emacs感觉比较好

btw 其实vscode也不是不行,我现在有时候就用vscode 做调试,vscode也有magit, vim 这些插件

在 linux 上安装 emacs ,然后 ssh 上去用 emacs -nw,已经在工作中用了一年多了,体验很好

1 个赞

折腾了好几天,走了很多弯路,包括自己写了2000多行伪的c++/c标准库头文件,最后发现自己采用的方法出乎我意料的简单:

把编译容器中的 /usr/include目录打包下载下来,然后在本地解压,然后在项目目录中、本地的 /usr/include目录中都写一个.clangd文件,其中要求clang++不要引用任何标准库头文件,然后把本地的 /usr/include 目录添加进去。

CompileFlags:
  Add: [-std=c++0x, -Wall, --target=x86_64-pc-linux-gnu,
  -nobuiltininc,
  -nostdinc++,
  -nostdinc,
  -isystem/Users/byhc/work/cpp1/usr/include,
  -cxx-isystem/Users/byhc/work/cpp1/usr/include/c++/4.4.4,
  -cxx-isystem/Users/byhc/work/cpp1/usr/include/c++/4.4.4/x86_64-redhat-linux,
  -isystem/Users/byhc/work/cpp1/usr/include/linux,
  -cxx-isystem/Users/byhc/work/cpp1/usr/include/c++/4.4.4/tr1,
  -cxx-isystem/Users/byhc/work/cpp1/usr/include/c++/4.4.4/backward,
  -D_POSIX_C_SOURCE=201103L,
  -D_XOPEN_SOURCE=600,
  -DBYTE_ORDER=1,
  ]
  Remove: [-arch]
  Compiler: /Users/byhc/.nix-profile/bin/clang++

然后,可能需要修改若干文件,我这里发现只需要修改 cpp1/include/c++/4.4.4/x86_64-redhat-linux/bits/c++config.h 文件,在文件末尾最后一个endif前增加:

typedef long ptrdiff_t;
typedef unsigned long size_t;

typedef __builtin_va_list va_list;
typedef __builtin_va_list __gnuc_va_list;

ptrdiff_t size_t这些类型在g++下应该是作为编译器自带的类弄了,我看头文件中没有明确定义,所以在这里补充。va_list本来挺难搞,因为一定需要编译器扩展,所幸clang++自己有 __builtin_va_list ,只需要定义别名就行。

此外,还需要把一些文件中 GCC 编译器的扩展去掉,我目前只遇到一个:

cpp1/include/c++/4.4.4/exception_ptr.h 中有个

#pragma GCC visibility push(default)
...
#pragma GCC visibility pop

直接删掉就好了。

========================================

以上是实践部分,据我观察,其实大多数头文件,所有系统都是通用的,相差的就是平台相关性的基础类型定义和部分编译器扩展,所幸这部分文件数量不多,我目前就遇到上面两个,改掉后,clangd就可以正常在mac上索引linux下的c++/c项目了,只是还需要编写.clangd文件,不过也还好。

你是在 Mac 的 Emacs 上开发,但是代码在 Linux 上编译?调试怎么办?

为什么不在 Linux 上运行 Emacs?

写的服务器程序,写完编译好要放测试环境测试/调试,本地是无法测试/调试的。

然后工作配发的电脑只有mac,或者windows。

windows的话虽然wsl也挺好用,但是配发的某品牌笔记本非常烂,实在不能忍,所以只能用mac。