行结束符

1. 问题

  • 为何各平台行结束符不同?

  • 跨平台开发应该使用哪种行结束符?

2. 分析

行结束符(end-of-line, EOL)是文本文件中用来表示新行(new line)的间隔,也称作断行符(line break)。

历史上,有三种 EOL:CR、LF 和 CRLF。其中:

  • CR (Carriage Return),即回车;
  • LF (Line Feed),即换行。

古典的 macOS 使用 CR 做 EOL,现在已经改为 LF,所以主流只有 LF 和 CRLF。

哪个更好呢?

从技术的发展史来看,CRLF 更直观。在机械打字机时代,CR 和 LF 分别具有不同的作用:LF 将打印纸张上移一行位置,但是保持当前打字的水平位置不变;CR 则将“Carriage”(打字机上的滚动托架)滚回到打印纸张的最左侧,但是保持当前打字的垂直位置不变,即还是在同一行。 当 CR 和 LF 组合使用时,就是将打印纸张上移一行,且下一个打字位置将回到该行的最左侧。Windows 采用 CRLF,说明微软的人是很技术思维的,就是耿直地认为:行结束就应该像打字机那样先 CR,再 LF。

但从存储和解析的成本来看,LF 更好。所以现在微软在 Windows 11 里也倾向于同时支持两者,目前就连记事本也能识别 LF 格式的 EOL 了。

只使用 LF 可行吗?

能统一肯定是好事!在写代码这件事上,只使用 LF,没啥坑。VS2022、VSCode 都能同时支持 CRLF 和 LF。

3. 实践

  1. git 设置
1
2
git config --global core.autocrlf input
git config --global core.safecrlf true
  1. 工程 .gitattributes 模板
1
2
3
4
*                   text=auto eol=lf
*.sln text eol=crlf
*.vcxproj text eol=crlf
*.vcxproj.filters text eol=crlf

有其它 Windows 特有,并且一保存就自动格式化为 CRLF 的文件,都设成 text eol=crlf

  1. 工程 .editconfig 模板
1
2
3
4
5
6
7
8
# Visual Studio generated .editorconfig file with C++ settings.
root = true

[*.{c++,cc,cpp,cxx,h,h++,hh,hpp,hxx,inl,ipp,tlh,tli}]
charset = utf-8-bom
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

华为擎云 W515 安装 Debian 12

1. 需求

GitHub 太慢,Gitee 老是被封,发邮件反馈好多次,至今给稣打上奇怪的标签。

https://gitee.com/umu618

于是直接使用 gitlab-ce 打造自己的 git 服务,实现真正的 Private 仓库。

2. 硬件选型

首先,上擸𢶍,一台 J4125,6GB 内存的机器。实测 6GB 内存不太够,淘汰。

看来需要 8~12GB 内存比较靠谱,手里还有 3 台 N100,内存分别为:LPDDR5 4800MHz 8GB、DDR4 3200MHz 32GB、DDR5 4800MHz 32GB,问题是 N100 这么高贵的核显不是浪费了?果断都淘汰。

后来,把 DDR4 3200MHz 32GB 的 N100 机器出给道友,并收了他的华为擎云 W515,硬件选型迎来完美结束——省电的 arm64 CPU(整机并不省电);8GB 内存;带不动 4K 的擸𢶍核显,一点都不浪费。

3. OS 选型

UOS 和 KylinOS 都玩了好几遍,它们都是桌面系统,有许多限制,不适合做 Server。

考虑上 Debian,但正常安装 Debian 11 和 12 都会遇到各种黑屏、无法启动。推测新内核无法启动 W515,是因为国产生态的开发比较保守,主要使用 4 和 5 这两个大版本,没给 6 的大版本适配。

最开始的解决方式是把 Debian 的内核换成 UOS 或 KylinOS 的,虽然启动报错导致启动慢,但又不是不能用。截图是 KylinOS 内核:

W515 信息

EFI 程序也是使用 Kylin 的:

W515 EFI

至此已经能够使用最新 Debian 发行版,并安装 gitlab-ce。

4. 后记

以上折腾完都快一年了,最近发现原来 Debian 10 (Buster) 的内核就是 4.19 系列,所以它的 arm64 版可以直接使用……

修复因防火墙故障导致的 winget 无法使用

问题

首次使用 winget,报无法注册 windows.firewall 扩展,防火墙无法启动。

相关问题

  1. https://github.com/microsoft/winget-cli/issues/4305

  2. 安装Microsoft Store应用时,系统无法注册 windows.firewall 扩展

分析

不仅是 winget 会因为防火墙故障而无法启动,其它 Microsoft Store 应用也可能遇到,说明这问题出在防火墙,而不是 winget。

经过排查发现根源是 Base Filtering Engine 服务无法启动导致。用 sc 命令可以发现,Windows Defender Firewall (mpssvc) 依赖 Base Filtering Engine (bfe),故 BFE 无法启动必然导致防火墙无法启动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ sc qc mpssvc
[SC] QueryServiceConfig 成功

SERVICE_NAME: mpssvc
TYPE : 20 WIN32_SHARE_PROCESS
START_TYPE : 2 AUTO_START
ERROR_CONTROL : 1 NORMAL
BINARY_PATH_NAME : C:\Windows\system32\svchost.exe -k LocalServiceNoNetworkFirewall -p
LOAD_ORDER_GROUP : NetworkProvider
TAG : 0
DISPLAY_NAME : Windows Defender Firewall
DEPENDENCIES : mpsdrv
: bfe
: nsi
SERVICE_START_NAME : NT Authority\LocalService

尝试

  1. 使用 sfc 修复几次,bfe 还是无法启动!

  2. 从另一台机器导出一份干净的 BFE 服务注册信息,导入故障机,依然无法启动。

  3. 后来想到:导入时使用的是当前用户身份,可能权限不太一样,于是检查 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\BFE 下每个键的权限,发现确实是不一样的。

  4. 给 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\BFE\Parameters 设置权限,添加用户 NT Service\BFE 即可。

参考

Base Filtering Engine (BFE)服务无法启动-CSDN博客

双拼输入法

用户故事

早在 2018 年,稣就因为鼠标手换用轨迹球,后来连键盘也开始敲不得了。

稣发现,同龄程序员似乎没这烦恼,大概他们都转行了规规矩矩地学会指法,而稣长期只使用双手的大拇指、食指和中指,而且必须看着键盘打。其中大拇指主要用来敲敲空格,所以基本上都在磨损食指和中指,长期下来,稣就输了!

但是似乎减少击键比学指法简单,于是大约从 2022 年中开始,稣选择中国人最擅长的弯道超车——学双拼。

实测

1. 小鹤

开始选择双拼方案时,第一印象是都差不多。选小鹤主要是觉得这是自然码的一种改进版,而且是中国人开发的,应该更懂汉字输入法。

使用大约两年,感觉小鹤挺适合稣。因为小鹤更多常见字集中在单手,对不会指法和盲打的人更友好。

2. 微软

但小鹤还是把稣惯坏了,使得学习指法被搁置,食指和中指的磨损依然远比其它手指厉害。听说改用微软方案可以练成少冲剑(;),稣便想一试,毕竟这是六脉神剑微软啊!

于是练了 2 周的微软双拼,少冲剑(;)大成,但发现两个问题:

  1. 手机上键盘布局不统一,iOS 和 Android 的 ; 位置不同,而且 iOS 的上两排原本和 PC 键盘一样垂直错开的,因为多了 ; 变成垂直对齐了,十分奇怪……

  2. 微软是固定零声母(默认为O),不自然,不太习惯。

iOS 上自然码系的键盘布局

iOS 上微软方案的键盘布局

3. 自然码

如图,自然码其实和已经熟悉的小鹤区别不大:

自然码键位

小鹤键位

两者有 15 个键是一样的:

相同的键

把自然码如下图这般移动 11 个键即得到小鹤:

不同的键

目前使用自然码将近一个月,这相对陌生的方案逼着稣使用正确的 PC 键盘指法,使得稣会继续用它。

辅助码

割爱!不管是 PC,还是手机,稣只使用系统原生的输入法,都不支持,就不想了。

安装 Arch Linux 和 Debian 双系统至同一分区

问题

之前,稣的服务器都用 Debian 和 Hyper-V Server,桌面则用 Debian、macOS、Windows,从不用不支持 Secure Boot 的 Arch Linux。

直到遇见一个需要在 Arch Linux 物理机下才容易编译的项目……那就装个双系统吧!

现状

Debian 的豪华 SSD 只分两个区:

  • /dev/nvme0n1p1:EFI 分区,64MiB;

  • /dev/nvme0n1p2:btrfs 分区,剩余空间。

没有 swap 分区,毕竟稣有 48GB 内存,而且从不使用休眠。

思考

  1. 重新分区显得格外 Secure Boot,毕竟稣就是因为某些系统强行分了 20~30GB 做系统的备份分区,而拉黑它。这可是高贵的 SSD,多一个分区就意味着空间利用率降低一分!系统和软件都能轻易地恢复,备份啥呢?依托答辩还占着 20~30GB 这么巨大的坑!这拿来备份数据不香吗?

  2. Debian 12 的 / 挂在 btrfs 分区的 @rootfs 子卷,据说其它系统可能用的是其它名字的子卷,所以它们天然是能和谐地装在同一个分区的。比如 Ubuntu 和 OpenSUSE(哦喷稣𢶍)用 @ 子卷。而 Arch Linux 出了名的啥都能(让)自定义,所以装在 @arch 子卷的话,还能和 OpenSUSE(哦喷稣𢶍)组个三系统。

  3. 安装顺序有影响吗?没有!虽然稣是先装的 Debian,但哪个先都行。只要装一个 grub 就行,那就用 Debian 的,Arch Linux 不装即可。

步骤

1. 安装 Debian

唯一要注意的是:根目录选择 btrfs 格式,其它请参考《快速安装 Debian》。

2. 把 /home 指向 @home 子卷

建议两个系统都这么干。因为虽然是双系统,但用户还是一套的好,避免精神分裂!这样的好处很多,比如:只要在任意系统里设置一次用户的登录公钥,就能在两个系统都生效。

1
2
3
4
5
6
7
# 在 Debian 上操作
sudo mount -t btrfs -o compress=zstd /dev/nvme0n1p2 /mnt
sudo btrfs subvolume create /mnt/@home
# 可能需要移动现有文件到 /mnt/@home
sudo umount /mnt
sudo mount -t btrfs -o subvol=/@home,compress=zstd /dev/nvme0n1p2 /home
# 改 /etc/fstab

3. 安装 Arch Linux

请参考以下链接:

注意:安装 Debian 时已经分过区,到这步,只需要创建子卷:

1
2
3
btrfs subvolume create /mnt/@arch
# 相应地,挂载 Arch 根目录所在子卷到 /mnt 那步改为
mount -t btrfs -o subvol=/@arch,compress=zstd /dev/nvme0n1p2 /mnt

然后,@home 子卷之前已经创建,直接挂载即可。

最后,**不要安装引导程序!**重启去 Debian,手动加 Arch 的启动项。这步解释起来麻烦,直接发一下 Debian 的 /boot/grub/grub.cfg 里的片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
menuentry 'Arch Linux' --class archlinux --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-9b30a786-55a7-4068-8886-226f147eef4d' {
load_video
insmod gzio
if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
insmod part_gpt
insmod btrfs
search --no-floppy --fs-uuid --set=root 9b30a786-55a7-4068-8886-226f147eef4d
echo 'Loading Arch Linux ...'
linux /@/boot/vmlinuz-linux root=UUID=9b30a786-55a7-4068-8886-226f147eef4d ro rootflags=subvol=@arch,compress=zstd nowatchdog
echo 'Loading initial ramdisk ...'
initrd /@/boot/initramfs-linux.img
}
menuentry 'Arch Linux fallback' --class archlinux --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-9b30a786-55a7-4068-8886-226f147eef4d' {
load_video
insmod gzio
if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
insmod part_gpt
insmod btrfs
search --no-floppy --fs-uuid --set=root 9b30a786-55a7-4068-8886-226f147eef4d
echo 'Loading Arch Linux ...'
linux /@/boot/vmlinuz-linux root=UUID=9b30a786-55a7-4068-8886-226f147eef4d ro rootflags=subvol=@arch quiet
echo 'Loading initial ramdisk ...'
initrd /@/boot/amd-ucode.img /@/boot/initramfs-linux-fallback.img
}
menuentry 'Debian GNU/Linux' --class debian --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-9b30a786-55a7-4068-8886-226f147eef4d' {
load_video
insmod gzio
if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
insmod part_gpt
insmod btrfs
search --no-floppy --fs-uuid --set=root 9b30a786-55a7-4068-8886-226f147eef4d
echo 'Loading Linux 6.1.0-21-amd64 ...'
linux /@rootfs/boot/vmlinuz-6.1.0-21-amd64 root=UUID=9b30a786-55a7-4068-8886-226f147eef4d ro rootflags=subvol=@rootfs quiet
echo 'Loading initial ramdisk ...'
initrd /@rootfs/boot/initrd.img-6.1.0-21-amd64
}

注意:直接修改 /boot/grub/grub.cfg 通常被认为是不好的,但这里的 Arch 是个不支持 Secure Boot 的擸𢶍,不用太客气。

答疑

  1. 这么做有啥好处?

    • 减少分区数量,提高 SSD 空间利用率,榨干每个颗粒。抠就要抠到极致。

    • 系统搞坏一个,还可能进另一个修。但比起虚拟机,没有安全性、健壮性上的优势。

    • 随时可以 chroot 到另一个系统。但比起容器,没有便捷性上的优势。

  2. EFI 分区 64MiB 够用吗?

    没翻过车,之前都用 40MiB 的,已经放大过。

警惕!劣质的 HDR 正在摧毁程序员的职业生涯

问题

有的屏幕看起来就容易眼睛疲劳,都不能愉快地写代码了!

故事

自从 2020 年,全面换成双 4K 显示器后,稣明显感觉眼睛不太够用!半天左右就开始无法直视屏幕。以为自己驾驭不了双 4K,吓得稣把它们分开使用。

但即使是单个 4K 显示器,看起来也比之前用两个 2K 累眼。即使换上 144Hz 的 AOC U28G2X/D 也没有改进多少。

稣一度以为人到中年就是不能再像之前那样能每天娱乐(但别人看起来是工作)18~20 小时都不会有任何不适。

解决

耿直的稣怎么也不会想到万恶的资本居然发现一种叫“8 抖 10”的技术,或者叫“8 位递色”,而开启伤害的动作居然是没深究就打开的“HDR”!

稣以前的双 2K Dell 显示器是不支持 HDR 的,当看到买来的 4K 显示器能支持 HDR,便尝试性地开启了。于是开启长达四年的八哥。

自从关掉 HDR,稣又测试了几次通宵写代码,除了饿,简直不能太爽!

有人说,价格超过 5000 元的显示器是可以开 HDR 的。也许吧!但两个就一万以上了……为了一个用不上的 HDR,何必呢?

PARTUUID

问题

blkid 的输出里有 UUID 和 PARTUUID,为何需要两套 ID?

分析

  • PARTUUID 是分区表级 UUID (Universally Unique Identifier),是 GPT (GUID Partition Table) 硬盘上所有分区的标准特性。因为它是从分区表中检索的,所以访问它时不需要对分区的实际内容做任何假设。即不需要理会分区的文件系统是哪种格式,比如 btrfs、ext4、FAT、NTFS 等。如果分区是使用某种未知加密方法加密的,则 PARTUUID 可能是该分区唯一可访问的唯一标识符。

  • UUID 是一个文件系统级别的 UUID,它从分区内的文件系统元数据中检索。只有当文件系统类型已知并可读时,才能读取它。

  • UUID 适用于所有层(块设备、分区、raid、luks、lvm),PARTUUID 仅适用于 GPT 分区。

解决

GPT 是 UEFI 的规范。Linux 诞生时,UEFI 尚未诞生,所以是先用 UUID,后用 PARTUUID。

UUID 的应用场景:

  • 默认情况下,/etc/fstab 里用的是 UUID,比如安装 Debian 12 时就写入 UUID,而不是 PARTUUID。

  • MBR 硬盘没有 PARTUUID,只能用 UUID。

PARTUUID 的应用场景:

  • efibootmgr -v 查看 EFI 启动信息,可以发现 EFI 使用 PARTUUID。

额外

UUID 的缺点是必须扫描所有设备的内容才能找到它们,毕竟 UUID 可以在任何地方。使用 PARTUUID,则只需检查分区表,因此更容易/更高效(但是需要有大量的块设备才能看出差别)。

通过 PARTUUID 挂载可以在没有 initramfs 的情况下工作,因此如果您想制作一个无 initrd 的系统,请使用 PARTUUID。

ext4 分区可以用 sudo tune2fs -U <UUID> device 修改 UUID,重新格式化、转换文件系统格式也可能导致 UUID 改变,所以实际上 /etc/fstab 里用 PARTUUID 更好一点点,除非您还在使用 MBR 磁盘。

快速安装 Debian

问题

前不久在知乎上看到有人说“安装 Debian 的体验很差,会卡很久”,还有人说“装了一两天”,稣心想:“怎么是相反的认知呢?哪里出八哥了?”

分析

目测是使用 netinst 映像,并且遇到网络问题。

这一点也不奇怪,比较奇怪的是,为何稣完美错过出八哥的条件?思考一阵后,得出这样的答案:

  1. 最早当然都是用完整安装映像在虚拟机里安装。也有直接用 qcow2 格式的云映像。

  2. 稣第一次亲自安装 Debian 是在一家区块链公司,一开始没有运维,只能自己上阵。但环境是 GCP、AWS 这些云,“安装系统”是不存在的,那叫“选择系统”,选好即可用。而且它们的网络都特别好,即使后来自己安装任何包,也都很快。

  3. 稣第一次使用 netinst 映像在物理机上安装 Debian,是在跨国公司的企业网络,能自动加速到新加坡网络……

  4. 稣在家里第一次使用 netinst 映像在物理机上安装 Debian,网卡没认出来……离线安装后,才找到一个 USB 有线网卡,终于连上网,手动改源到 USTC 后,再继续安装的。

  5. 再后来已经知道 debian-security 的坑了。详见《在华硕灵耀 X 纵横上装 Debian 桌面的经验》。也知道如何在安装时,使用极客的方式改变 debian-security 源。

事实上,在国内安装 Debian 大概率会因为 debian-security 源访问十分缓慢而花费几个小时。而且,在安装界面选择源无法解决这个问题!因为无论您在安装界面怎么换源,换掉的只有 debian 源,而 debian-security 源始总是默认的 http://security.debian.org

解决

显然,直接使用较庞大的完整安装映像可以很容易解决这个问题。但带来的问题是,下载 ISO 和刻盘时间都变长。最可怕的是,需要下载的 ISO 将近 4GB。对于稣这样的穷人,用于安装的 U 盘只有 1GB,这个方式根本不可行!所以,在安装时,使用极客的方式改变 debian-security 源,才是正确的方式。

思路大致如下:

  1. 在选择源的界面,选择适合的国内源,比如在厦门、上海,都可以使用 USTC。

  2. 下一步是“Select and install software”,也就是开始慢的第一步。在这步界面下,按 Ctrl+Alt+F2,再按回车,打开一个控制台。

  3. 在控制台里换 debian-security 源,注意位置是 /target/etc/apt/sources.list,使用 sed 换即可,例如 sed -i.bak 's|security.debian.org|mirrors.ustc.edu.cn|g' /target/etc/apt/sources.list

  4. 此时源修改并未生效,如果按 Ctrl+Alt+F5 回到安装界面,会发现依然在慢吞吞地下载。所以,还需要把当前使用默认源的下载会话给杀掉。还是在 Ctrl+Alt+F2 控制台里操作,先 ps | grep http 找到 /usr/lib/methods/http 进程的 pid,然后 kill 掉。

  5. 按 Ctrl+Alt+F5 回到安装界面,键鼠操作,重试这一步即可使新的 debian-security 源生效,后面将快很多。

Windows 平台安装安全版掩耳(Thunder)

需求

下载小文件,一般直接用浏览器。中等规模的,则一般用 aria2。大文件,还是要用 P2P 工具。

在国内,拥有 P2SP 的掩耳在下载 iso 等大文件时,无疑是具备巨大优势的。

比如,前几天稣下载一个 Windows Server 镜像,用 aria2 是 2.8MB/s,而掩耳则达到 6.1MB/s。

但是!Window 版掩耳的界面确实复杂而龟速,还有许多稣不需要的功能,比如它带了一个 WFP 驱动,又没开源,怎么知道它除了监控流量,还有没有监控流量呢!还有那个分配空间用的服务,又没开源,为啥给它系统权限?总之,不够安(fh)全(xb)!

思路

如果在 Linux 上,可以使用 Docker 版,或者干脆装在虚拟机里。

Windows 也可以装在虚拟机里,但损耗比较大,而且操作麻烦。另一个方案是“Windows 沙盒”,需要使用一个类似“远程桌面客户端(mstsc)”的界面操作,比虚拟机方便,但还不够方便。

更好用的方式是通过 WSL 使用 Linux 版掩耳,它本身就是精简版,一次性解决船部烦恼。

安装流程

1. 安装 WSL Debian

在 Windows 上操作:

1
wsl --install -d Debian

2. 安装掩耳

这步在 Debian 上操作,由于稣的 Windows 是 ARM64 版本,所以以下安装的是 arm64 的掩耳:

1
2
wget https://archive.kylinos.cn/kylin/partner/pool/com.xunlei.download_1.0.0.1_arm64.deb
sudo dpkg -i com.xunlei.download_1.0.0.1_arm64.deb

x64 的 Windows 是这样:

1
2
wget https://archive.kylinos.cn/kylin/partner/pool/com.xunlei.download_1.0.0.1_amd64.deb
sudo dpkg -i com.xunlei.download_1.0.0.1_amd64.deb

3. 安装依赖库

目前掩耳是安装了,但还跑不起来,除非您的 Debian 本来已经安装过桌面环境。以下安装依赖库:

1
sudo apt install libgtk2.0-bin libx11-xcb1 libxtst6 libxss1 libnss3 libasound2 libdbus-glib-1-2

此时已经可以使用 /opt/apps/com.xunlei.download/files/start.sh 启动掩耳,但是中文字体都口了。

4. 安装中文字体

1
sudo apt install fonts-wqy-zenhei

大功告成!