跳转至

一个碌碌无为的上午

昨天把我的YYCC常用基础函数整合库库的所有基本功能写完了。今天一早起来打算测试一下它在Linux上的编译情况并修复一些错误。首先在Windows上用Visual Studio做最后一次编辑,把一些没有用#if WINDOWS_ONLY的宏包裹起来的Windows专用代码包裹起来,因为这些代码不能在Linux下编译并使用。然后提交,就准备开始做测试了。我的计划是使用以前配置的Debian 11 Bullseye VirtualBox虚拟机进行Linux上的测试,因为之前的libcmo21相关库的Linux平台测试也是在这台虚拟机上测试的。我万万没想到原定1-2个小时的debugging,最终会消耗我一整个上午的时间,且到中午也只是刚刚开始debugging,一直到下午才debugging完成。

当我满心欢喜地启动虚拟机,用git clone了项目准备开始测试的时候,我心血来潮想检查一下CMake版本,毕竟YYCC在几个版本前由于使用了target_sources中的FILE_SET功能,将最低CMake要求从3.12提升到了3.23。这一检查不得了,CMake输出的版本是3.18,这显然没法用于项目的配置。我当然可以将target_sources中的FILE_SET暂时移除以求可以正常调试,但考虑到总不能以后都那么阉割项目来做调试,还是升一级下CMake更好。我首先想到的就是能不能通过apt更新,一通sudo apt update之后,发现CMake的最新版本就是这个3.18,没有更新的了。

这台虚拟机上安装的Debian 11 Bullseye是2022年安装的,才过去不到两年,按照我个人的感受,这并没有多长时间。考虑到Debian一直以来“坚如磐石”的软件包策略(指稳定版软件包的版本低得可怜),就在水友群里发了几句牢骚。没想到菠萝提出为什么不更新到最新版本,然后就是什么改sourcelists然后update+full-upgrade之类的,给我这个Linux新人整的云里雾里的。我去Debian package网站搜索了一下,确实,Debian 12 Bookworm的CMake版本就已经是3.25了,满足了调试需求。然而,我本人从来没有在Debian上进行过升级。Debian相较于那些滚动发行版,例如Arch来说,升级并不是简单地更新全部的软件包,我看过升级相关的文章但从未实践过,因此这样做有很大风险。而且我只是想调试个程序,不是来升级系统的。于是我选择了另一套方案,就是从CMake官方那里,手动安装最新版本的CMake。

很快我就找到了官方提供的最新版本CMake的下载地址。大家似乎都在推荐通过编译安装的方式来安装CMake,而不是像Windows那样,使用编译好的可执行程序。这可以理解,于是我也下载了源码包并打算这样安装。首先我需要卸载CMake,虽然不卸载CMake,新老版本共存也没有任何问题,但是总归有些时候它俩可能会打架,也许是某些不为人知,至少是我不知道的隐秘设置忘了设置,导致我不知道什么时候就用了旧版,于是先卸载就成了一种稳妥手段。查到了两种方法卸载CMake,一种是sudo apt remove cmake,只是简单地删除CMake的软件包,另一种是sudo apt purge --auto-remove cmake,删除CMake和所有自动安装的没有被依赖的包,同时删除所有配置文件。第二种方法看起来就很危险,而且据说很容易把系统搞挂,所以我选择了第一种保险方法,只是硬盘多占了点空间而已,总比系统挂了好。卸载完了之后就开始安装CMake了。

安装CMake的一个最现实的问题就是,我没有办法把任何文件放到我虚拟机里。由于众所周知的网络原因,从虚拟机里直接下载CMake源码包的速度极其低下,我只能在我的Windows主机上通过合适方法把源码包先下载下来,然后尝试将其放到我的虚拟机里。但我目前的这个虚拟机有个问题,它没有安装VirtualBox Guest Addentions(后简称VBox GA),而共享文件夹功能必须要安装VBox GA才能使用。于是我尝试给虚拟机安装VBox GA,但是无论我怎么设置虚拟光驱,虚拟机中的Linux都毫无反应,无论是/media/cdrom,还是/mnt下,都没有任何内容。于是我考虑是不是VBox版本过旧问题,因为我曾记得这个虚拟机当初没有安装VBox GA的原因就是运行安装程序的时候提示Linux版本不受支持(也许和另一个事情记混了)。正好,我记得近几年VBox爆出了不少高危漏洞,因此升级一下也挺好的(当初不喜欢升级VBox的原因是从VBox 5.x升级到VBox 6.x之后3D性能极度降低)。我目前的VBox版本是6.1,按照官网的最新版本下载后升级到了VBox 7.0。升级完毕后我想到VBox GA的ISO本身也得更新,于是我在VBox官网找了半天没找到VBox GA ISO的下载地址,最后发现我文件夹里的VBox GA ISO已经被替换过了,意味着它已经更新到最新版本了,于是放弃查找,但我仍然对于在VBox官网上找不到任何VBox GA ISO独立下载的链接感到奇怪和不能理解。经过一阵相同的折腾后,我还是没法在Linux看到VBox GA ISO光盘映像。

此时菠萝又提出,VBox GA已经被收录进Debian package中了,我可以直接安装对应的软件包。于是我立即使用apt搜索,首先搜索的是apt search vbox,没有任何有效结果。后来按照菠萝都建议搜索apt search virtualbox,还是没有任何结果(在这期间为了避免去搜索包描述,去查看了apt的帮助文档,学习了--names-only选项)。于是我去Debian package网页查找virtualbox,是可以查询到对应的包的,我百思不得其解为什么我本地搜不到。终于我的目光停留在了Debian package网页上的那个non-free红色标识上,是不是我没有开启non-free呢?于是立即搜索为Debian添加non-free的方法,找到了相关文章。立即按照其中给定的方法,使用sudo nano /etc/apt/sources.list打开源配置文件,然后为每一项后面加上了contrib non-free来开启non-free。保存后运行sudo apt update,然后再查询,果然找到了对应的包。但是按照包的描述,这似乎是用于Linux上的VBox的包,而且其版本非常低,主机VBox已经升级到了7.0,而搜索得到的包版本似乎是6.1。因此这个方法也被迫放弃,因为不相同的大版本号可能会造成不必要的问题,即便它可以安装。于是我决定另寻他法来解决这个文件传入问题。

此时我想到VS Code是可以在连接后通过拖放的方式直接传入文件的,而VS Code在上一次调试libcmo21后已经配置好了,可以直接连接虚拟机,于是我决定立即启动VS Code并尝试连接虚拟机。然而并没有成功,VS Code反复向我索求登录用户的密码,而通过日志可以看出,它反复爆出Exit Code 42错误,以及所谓的XHR failed错误。经过查询后得知,这通常是网络问题导致的。VS Code在连接到远程时,需要在远程端下载一个code-server在远程机器上。而当网络不通畅,下载受阻,被迫终止后,VS Code通常会爆出这个错误。网络上的相关文章给出的建议是手动下载并解压code-server,然后就可以顺利连接。此时我忽然想到,我的VS Code在上一次调试后进行过一次更新,这可能就是它需要重新下载code-server的原因,因为上次的code-server已经不能用了。

我很轻松地从日志里找到了code-server的commit数据,是903b1e9d8990623e3d7da1df3d33db3e42d80eda。然后根据指示构建了网址https://update.code.visualstudio.com/commit:903b1e9d8990623e3d7da1df3d33db3e42d80eda/server-linux-x64/stable,成功下载到了code-server。现在的问题是,我需要把它发送到虚拟机里,这就形成了一个死循环,我需要发送文件到虚拟机,但我需要这个文件才能发送文件。有人会说可以搭建一个FTP服务器来传入,这是一个方法,但我没有相关工具,我也不知道如何在Linux的命令行模式下下载FTP上的文件(我猜wget就可以?)。此时我Windows主机上是有WinSCP这个软件的,但我当时已经被冲昏了头脑,完全想不到这个软件,一心只想把文件塞进去,最终又回到了尝试安装VBox GA上。

我决定弄清为什么我无法在Linux上加载光驱。一番寻找后,我最终结合网络文章和我以前的经历,想到了可能是没有挂载的问题。Linux上的某些设备是需要挂载到一个位置才可以正常访问的,而纯命令行下Linux并不会像有DE的Linux或Windows那样自动为你挂载。于是我查询了mount的使用方法,使用mount /dev/cdrom /mnt/cdrom将光盘挂载到了/mnt/cdrom下,果然在其中看到了VBox GA ISo中的内容。我当即将其拷贝到了~/VBox下,因为我以前的某个时候试过在光盘挂载目录下直接安装过,但是给我报告权限错误,因此我决定将内容全部拷贝出来再安装。拷贝完毕后,我使用umount /mnt/cdrom将其卸载。然后趁机学习了eject的用法,使用eject --cdrom弹出了光驱。在有DE的Linux下,DE会在图标上给用户提供一个弹出按钮,而在命令行下,这一操作需要你手动进行。弹出意味着介质可以被安全卸载,如果直接拔出,就相当于是暴力插拔,很容易造成错误。

接下来就是稀疏平常的安装VBox GA了,我已经安装过许多次,执行sudo ./VBoxLinuxAdditions.run,等待安装完毕,然后重启系统就可以了。然后我就兴冲冲地去/media下去访问sf_开头的VBox共享文件夹了。遗憾的是,它提示我没有权限,使用chmod +rw也没有用,只有root用户能够读写,这可不行。使用ls- la显示了一下文件夹的属性,其所有者为vboxsf。隐约记得我曾今遇到过这个问题,查询后得知,是当前用户没有加入vboxsf用户组所致。使用sudo usermode -a -G vboxsf yyc12345去把我加入vboxsf组中。此时我已经没有心思去想usermod是个什么指令,-a-G又是什么参数。一心只想尽快开始调试程序。输入后重新登陆,就可以正常访问共享文件夹了,赶紧将下载好的code-server拷贝到~中。

接下来就是将下载好的code-server写入到~/.vscode-server/bin/903b1e9d8990623e3d7da1df3d33db3e42d80eda。首先我删除了这个文件夹,然后使用tar -xzvf code-server.tar.gz将压缩包解压到当前文件夹,然后立刻就跑去用VS Code连接,结果依旧是连接失败。细查之下发现解压的操作做错了,文件夹里多套了一层文件夹,原来是解压命令少抄了一个参数--strip-components 1。这个参数可以将压缩包内的路径剥离一层,体现在外部的效果就是多套的一层文件夹没有了。我只能删除多余文件并重新解压。

继续尝试使用VS Code连接,VS Code不再提示正在下载code-server了,但仍然连接不上,查看日志发现有ln创建硬链接失败的字样。查询后得知,可能是之前的不正确的连接的遗留问题,遂再次进入~/.vscode-server/bin/903b1e9d8990623e3d7da1df3d33db3e42d80eda,按照说明将.target结尾的文件和硬链接(没发现)全部删除。再次使用VS Code连接,这次终于连接成功。至此我才解决了连接虚拟机的问题,还没有解决CMake问题,更别说调试了。

不过好在只要VS Code能连接上,一切都简单了。我立即传输了CMake的源代码文件,然后按照指示运行了sudo ./bootstarp,不知道为啥它检测到的是我不用的GCC编译器,而不是我默认的Clang编译器。不过这不重要了。接着运行make进行编译。可能是我给虚拟机分配核心数和内存过少的原因,也有可能是我的主机已经过时的原因,编译速度非常缓慢,我实在等不及了,终止了编译,打算使用预编译版本直接进行安装。

首先删除了CMake的源码包和编译文件夹。然后按照教程,先在主机上下载了预编译包,然后顺利将其传入了虚拟机。接着教程指示我创建/opt/cmake以容纳我安装的CMake本体。我对Linux,或者UNIX的文件树设计非常地不熟悉,我对于哪些文件夹具体是做什么用的一无所知,只对一些经常用到的,例如/home/etc等有印象。一番查阅后得知/opt是用来安装可选软件的,于是放心大胆进入,发现VBox GA也是安装在这里的,心里感到更加安心,于是迅速创建好了/opt/cmake。接着教程指示执行sudo sh cmake-3.29.6-LINUX-x86_64.sh --prefix=/opt/cmake来安装CMake到/opt/cmake。执行后是阅读许可条款以及确认安装位置是否需要嵌套文件夹的选项,同意条款和选择不嵌套后安装顺利完成。最后教程指示执行sudo ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake创建一个软链接,这样就可以访问到我安装的CMake了。我查阅了/usr/local/bin的含义,却没找到完全匹配的相关资料,只是说用户的本地程序可以放在这里,于是我也接受了这条指令并执行。然后回到home目录,查看cmake版本,显示为3.29。至此我才解决了我一开始要解决的问题,即CMake版本过低,此时已经接近上午结束了。

接下来就是调试部分了。CMake配置,编译,修正都很顺利,但有一个不知原因的意外错误,想用lldb调试一下。结果发现不知为何我没有在虚拟机中安装lldb,我记得以前安装过的啊?于是只能尝试安装。当时脑子已经是一滩浆糊了,随手就运行了个sudo apt install lldb去安装了。运行完后才忽地想起,默认的lldb版本可能并不是我想要的。之前这台虚拟机安装clang的时候,clang包指向的clang版本过低,是11,为此我特意直接安装了clang 13的包,并没有安装clang,而这次的lldb会不会也一样呢。我使用apt search lldb --names-only搜索包,果然发现安装的是lldb 11,而不是lldb 13,于是只能卸载lldb包后再显式指定安装lldb 13的包,为了和clang版本保持一致,也是为了不会有任何版本上的问题,毕竟用lldb 11调试clang 13生成的文件,谁知道会不会出什么问题呢?安装后我又脑残地执行lldb,显示没有这样的命令,想了一下,才知道要执行lldb-13才可以,clang也是同理,得执行clang-13

打开lldb后,凭借着以前记录的lldb调试命令手册,成功加载了程序,但在执行断点命令b main.cpp:179时,显示找不到对应位置。思考了一会后想到,可能是编译的时候默认编译成了Release版本,导致调试内容丢失。于是回到CMake中去找配置编译版本的配置选项,查了一圈,试验了一圈后,知道了加上-DCMAKE_BUILD_TYPE=Debug就可以了。但看其他人说法,他们说CMake默认就是Debug编译的,相反,它们需要手动指定Release模式以在最终输出中取得可用于生产环境的最终文件,不知道为什么在我这这种情况是反过来的。我没有闲心去管这些了,火速加上参数后重新配置CMake并编译,然后就可以正常调试了。

后面的调试等操作得益于第一次使用lldb时留下来的笔记,就非常顺利了,也没有其它意外之外的事情发生。至此,这个碌碌无为的上午算是结束了。