开发工具链
工欲善其事必先利其器。在理解了操作系统、编译原理等知识之后,选择自己的代码编辑器以及掌握构建工具、shell脚本、编译器、调试器、性能分析器等工具就是重中之重了。我选择了以vim为基本编辑器,以CMake为构建工具,然后在不同的平台上选择不同的shell脚本和编译器。
之所以有这样的选择,主要是因为在服务器端编程,很多情况下你没有办法物理上接触到服务器的,只能通过ssh方式连接到服务器。这也包括Windows服务器,在Windows10之后有了openssh支持方便了很多。所以后续阅读中请以ssh连接为背景来理解这些工具。
vim
关于vim的使用方法,我就不着重介绍了,网络上有很多的资源。我主要介绍一下自己的配置方法。
我这里只想提下如果你的vimrc配置文件写错了,在进入vim时候会出现一片空白通知你配置文件错误,但是又没有详细说明。这时候用vim -D进入开发者debug模式,可以逐行运行配置文件中的语句,对于查错非常有帮助。还有提醒一点是ssh连接到Windows 10后,默认cmd的编码方式不是utf-8,要通过命令chcp 65001
切换,这对于后续工具使用非常重要。
关于vim的使用有一些很好的链接:
vim在windows下的编译
Windows下的vim编译问题。再git clone完vim源代码之后,需要注意两个文件:
- READMEdir文件夹下的README_dos.txt文件,告诉你如何配置vim的运行环境;
- src文件夹下的文件INSTALLpc.txt,告诉你如何编译vim二进制文件
需要强调的是如果要编译支持python需要用到命令
nmake -f Make_mvc.mak PYTHON3=\path\to\python3 DYNAMIC_PYTHON3=yes PYTHON3_VER=python3_version
这样可以在src文件中生成所有的二进制文件。然后需要在你想要安装的vim文件夹中拷贝这些二进制文件,并且要把源代码中的runtime文件夹也要拷贝到二进制文件位置,然后设置环境变了$VIM为该位置,具体可以看README_dos.txt和INSTALLpc.txt中的介绍。
vim的配置
写代码一般需要这些功能:
- 自动补全
- 查看函数原型来补全参数
- 查看和跳转声明和实现
- 显示当前文件的类、对象、函数等
有很多的文章都讲到了如何配置。这里推荐韦易笑的文章《vim 8下c/c++开发环境搭建》,文章是2018年写的,里面推荐的vim插件都非常的新。他在他知乎文章里也写到目前的自动补全方式主要分为静态分析方法和LSP方法:
- LSP就是language server protocol,由微软提出来的协议并建立了官网,vscode的c++插件也是基于LSP开发的。LSP官网上列出了一些具体的实现,比如clangd、cquery和ccls,都是比较新出来的服务端还不够稳定,相信会越来越好。服务端配上vim的lsp客户端插件比如vim-lsp就可以进行自动补全了。
- 静态分析方法主要是利用gtags或者ctags来做分析,比较老的插件omnicppcomplete就是利用的ctags
ctags因为年代久远,目前主要使用的都是universal-ctags,编译需要使用automake、autoconf和pkg-config三个工具,而且可以把编译好的二进制文件改名称为比如uctags防止和macos上的默认ctags重名。静态分析方法是比较快的,对于大型源代码的浏览是非常方便的。浏览源代码的话除了要生成tags文件外,还需要一些插件支持比如vim-gutentags用于自动生成tags,LeaderF用于显示函数列表。
简单介绍一下Universal-Ctags,不仅能够处理定义,还能处理引用。主要概念分为fields、kinds、extras和roles。
- fields包括语言对象的名称,所在文件位置,文件中查找的模式,文件中的行号。fields也可以说是tags文件中对应的格式。
- kinds指的是fields中的语言对象,你想选择那些,比如变量、函数是否要记录下来,可以选择的。
- extras是额外选项,应该算是kinds的补充,因为kinds只会包含文件中存在的字段,但是extras可以包含比如匿名函数对应的名字,这种名字并不是在源文件中真的存在的。
- roles是Universal-Ctags才有的概念,主要是针对于引用概念,比如被include的文件名称会被标记为roles是头文件。
分享我为UE4生成ctags用的命令,切记要用用–format=1来保证生成的tags的格式是vim能够识别的原生格式。
ctags -R --format=1 --kinds-c++=+dfghmstuvcnZ --fields-c++=+{specialization}{template}{properties}{captures} --languages=c++ -f UE4 <UE4_DIR>
vim-plugin
vim-plugin支持并发操作,比vundle快很多,配置也比较简单,推荐使用这个进行管理vim插件。
cquery
cquery是基于微软公开的LSP的服务端,安装也非常的方便,git clone之后按照传统的cmake配置和编译即可,然后将其放到PATH环境变量中。不过在Windows下并不推荐采用cmake生成的compile_commands.json来提供路径给cquery,因为clang在Windows下比较难用,cmake会无法正常配置的。clang-cl的使用大家可以尝试一下,我总是链接失败就没用了。
vim-lsc
vim-lsc是基于LSP的客户端。在微软的官网上是有很多选择的,不过我个人还是很喜欢这个插件,功能比较精简正好都是我需要的。安装也非常的方便,在配置文件中增加Plug 'natebosch/vim-lsc'
即可。
在$HOME\_vimrc
文件中如下配置
let g:lsc_server_commands={'cpp':'cquery --init="{\"cacheDirectory\":\"<path>\",\"discoverySystemIncludes\":false}"'}
这里的discoverSystemIncludes是是否进行编译器的include文件夹推断的,而且会对clang++和g++对都推断一次,如果你的操作系统比如WIndows一般都没装g++,会产生大量的错误出来,特别恶心。所以这里设置成false可以关掉这个功能,我发现作者是默认设置这个打开的,因为他就是在linux上开发的吧。
vim-airline
vim-airline能够在vim底端显示一些状态,非常实用,因为你很多时候很想知道目前在整个文档的哪个位置,现在的编码格式是什么。还有一点是,现在的编辑模式是什么,方便切换。
CMake
一个最简单的CMakeLists.txt如下所示:
project(projectname)
add_executable(targetname sourcefilelist)
作为构建工具,CMake的目的是描述源文件之间的关系,以及目标是什么。这里就不得不提到库的概念了,CMake提供了对库的支持。在add_executable语句之前,加入link_directories可以添加动态库,加入include_directories可以添加静态库,添加target_link_librares可以逐个动态库文件加入到链接过程中。除此之外就是对一些CMake变量的记忆,能够帮助更快地将源文件之间的依赖关系描述清楚。还有Find语句的使用,提高了CMake模块的利用率,这里不再蛰述。推荐创建CMake的Kitware公司写的一本书《Mastering CMake》。
源码查看工具
以前都是听别人说SourceInsight,后来自己搜了一下发现这个工具好像停止更新了。无意之中发现一个也很不错的工具,叫做SourceTrail,不仅可以实现定义跳转,而且还会帮你把类图画出来,这是非常棒的。因为很多时候,我们其实想要知道的就是类之间的关系,看单个类其实意义不大。这个工具有VS的插件,也有vim插件。一般在Windows平台上没有cmake工具的话,很难生成compile_commands.json文件,这个vs的插件可以帮你生成!实在是太方便了!不过我自己尝试过发现,似乎启动Visual Studio的时候要用管理员权限,否则这个插件会卡住。
Shell脚本
在Windows上就是cmd和powershell,在UNIX上就是bash了,当然也有其他变种,最流行的就是bash了。Shell脚本的具体语法,我也不具体多说了,主要分享一些自己的经验。
我比较喜欢用微软新出的Windows Terminal工具,界面非常的漂亮,渲染是通过DirectX来实现的。
Windows下的UNIX环境
肯定会想到WSL的,但是我更喜欢用MSYS2工具。到清华大学的镜像源中下载安装包,安装好后默认打开是弹出个窗口,非常的不好看。但是我们可以通过配置Windows Terminal实现将MSYS2嵌入到里面,打开WT的配置文件写入
{
"guid": "{<your_guid>}",
"name": "MSYS2",
"commandline": "C:/msys64/msys2_shell.cmd -defterm -no-start -use-full-path -here -mingw64",
"colorScheme": "Novel",
"icon" : "C:/msys64/msys2.ico",
"closeOnExit": true,
"startingDirectory": "C:/Users/svandex"
}
这样可以在WT中开启新的选项卡而不用弹出黑框。
环境变量
环境变量说白了,就是当你打开Shell控制台的时候,在该控制台进程中可以用的变量。任何进程加载到时候都需要加载环境变量的,shell程序也是一种程序,也会加载环境变量。
比如最常用的Path环境变量,控制台用于寻找可执行文件就在Path中寻找。在Powershell中将环境变量env当作了Provider,可以像文件系统一样在其中浏览和编辑,可以使用Get-Child也就是ls命令。注册表HKLM和HKCU也都是Provider,可以浏览和编辑。在Bash中的话,环境变了要通过$来获取,直接方便。
在Windows上用命令行开发,非常支持将开始菜单下Visual Studio 2017里的命令行工具(本质上是launchdevcmd.bat脚本)放到特定的文件夹下,当你ssh连接到Windows时,调用这个命令行工具可以设置很多环境变量。在%vsinstalldir%\common7\tools
下有好几个bat脚本文件:
- launchdevcmd.bat 开始菜单中的visual studio prompt源文件调用vsdevcmd.bat
- vsmsbuildcmd.bat 调用vsdevcmd.bat但是不设置winsdk
- vsdevcmd.bat 运行所有的bat脚本
在%vsinstalldir%\common7\tools
下还有vsdevcmd文件夹,里面又有core文件夹分别对应了各种开发环境下的环境变量设置,ext文件夹对应了一些vsdevcmd.bat执行时调用的bat文件。如果熟悉这些脚本文件,比如只想载入c++相关环境变了,执行vcvarsall.bat就好了。
比较遗憾的是并没有在Windwos SDK文件夹中找到设置环境变量的相关脚本,只能通过先调用vsdevcmd.bat得到%windowssdkbinpath%等环境变量后再进行文件夹切换cd后执行命令,并不能直接将一些二进制文件添加到path环境变了中。
关于微软的其他官方脚本文件,可以在相应的文件夹下搜索*.bat
就可以找到。
包管理器
在UNIX中有各种包管理器,macOS中有homebrew,ubuntu中有apt,但是在Windows中我想着重推荐两个包管理器:chocolatey和vcpkg。其中chocolatey本质上是一些powershell脚本,可以让你从官网下载应用程序安装到电脑上,而且还支持命令行卸载软件,非常方便。而vcpkg是微软推出的库文件下载工具,可以通过vcpkg install opencv命令安装opencv的动态库和静态库,支持自主更新非常的方便。
编译器
既然编译器是工具,我们也不要深究编译器的内部实现,工具用起来就需要知道它的选项有哪些。常见的编译器有Clang、GCC和MSVC,除了GCC之外,Clang和MSVC都分为前端和后端。其是Clang就是前端,后端是LLVM,全称应该是Clang/LLVM简写成Clang。而微软的编译器MSVC的前端和后端分别叫做C1和C2。现在微软在VS2017中提供了以Clang为前端,C2为后端的编译器,不过现在据说bug还比较多。
- Clang/LLVM的编译器选项,在Windows上最好下载预编译版本,和boost一样自己编译都是非常耗时间和麻烦的事情。在Windows上是可以单独运行的,不需要msvc。
- MSVC的编译器选项,在Windows上编程的必选,不过为了用vim我还是需要安装clang
- GCC的编译器选项,还是很多Linux发行版的默认编译器
调试器
在linux下主要就是GNU/gdb调试器,也有用LLVM/lldb调试器的,这两个调试的命令相近,使用手册或者网上的教程也很多,我不在蜇述。gdb -tui
的字符界面用起来还不错。
在Windows下主要用到的命令行调试器是cdb,这篇文章是以ssh连接服务器开发为基础,所以我也不介绍GUI的windbg了。可以使用cdb -? >> <path\to\save\text>
来存储cdb自带的帮助文档查看使用方法,在微软的官方帮助文档上也有相应的文档。
额外提到的是,不建议使用Visual Studio Installer来安装Windows SDK,因为它默认是不给你安装Debuggers For Windows也就是调试器的,因为Visual Studio自带图形化的调试器。我们可以在微软的这个网站上下载SDK来安装调试器。安装完以后调试器的地址在%WindowsSdkBinPath%
,这个环境变量通过调用Visual Studio Prompt可以得到。
辅助工具
我使用vim和youcompleteme的原因在于,很多时候对于服务器来说都是没有显示器或者离服务器距离非常的远,这个时候就只能通过ssh连接了。而还有几种情况需要我们有额外的工具在ssh之前解决:
- 当你的笔记本和服务器直连或者通过路由器连接,但是你并不知道服务器的ip是多少。这时候需要用到nmap端口扫描工具可以快速定位服务器的ip,当然如果路由器连接的设备非常多的时候,你要不是通过nmap -A扫描获得服务器名称来判断ip,要不然就是已知服务器网卡的MAC地址来通过arp包来判断了。
- 当服务器只能通过无线网络进行互联网访问,你才能进行库安装等操作时,你需要用到如debian上的nmcli网络管理工具进行网络的连接。其他linux发行版应该有类似的工具,可以掌握一下。
- 当服务器有多个网卡时,手动编辑路由表是个很重要的能力,因为网卡也是有优先级的,你发出去的数据包先经过哪个网卡是需要手动编辑路由表实现的。当你有本地局域网和能连接互联网的无线网时,你会发现登陆百度总也上不去,这是因为数据包优先通过本地局域网,但是本地局域网找不到百度服务器。这需要设置无线网卡优先级更高,才能实现。
除此之外,我还推荐使用tmux工具,英文叫做terminal multiplexer也就是屏幕多用工具。很多时候我们执行一些命令需要时间,命令不会立即返回,那么我们要做别的工作又要重新打开终端,这太不方便了。我们使用tmux可以将执行中的终端隐藏在后端,继续进行我们的其他工作。
总结
这四大工具使用地越熟练越能够提高你的效率,尤其是vim的vimscript如果能够很好地利用起来,能够自动化处理很多东西,需要在以后的日子里多加练习。
更新
2018.12.18: 之前的文章是用Vundle来管理vim的插件的,最近看了韦易笑的文章发现用vim-plugin速度快很多,而且配置方便。另外发现了LSP这个好东西,这两年用YCM实在是配置起来蛋疼啊,逐渐转移到cquery和clangd去做LSP后端,vim-lsp作前端的配置方式了。现在就开始尝试起来。