【GSL 系列 4】为什么需要 gsl::not_null?

问题

  • 为啥要用 gsl::not_null?什么时候用?

分析

gsl::not_null 修饰指针,主要有两个目的:

  • 提高可读性。它相等于给代码写了一份注释,说明它修饰的变量不能为 nullptr。
  • 提高执行效率。对一定不会是 nullptr 的变量反复判空,怎么说都是白费力气。

它主要用于函数的:

  • 参数。说明这个参数不接受 nullptr。
  • 返回值。说明这个函数不会返回 nullptr。比如说,它恒返回一个 static 值/引用。

感想

本文大概率是 GSL 系列的最后一篇。GSL 有部分已经被 C++ 20 的 STL 覆盖,比如 gsl::byte。众所周知,现在 C++ 20 是主流……所以本系列只划了 4 个重点,其它类可以选修。

  • gsl::final_action

  • gsl::narrow_cast

  • gsl::owner

  • gsl::not_null

挑选的这 4 个类,主要贯彻 C++ 核心指南 提到的以下原则:

  • P.1: 在代码中直接表达你的想法

  • P.3: 表达你的设计意图

  • P.5: 编译期检查优先于运行时检查

  • P.8: 不要泄漏任何资源

最后,GSL 的定位是基础,也就是说它本身应该是一看就懂,不需要特地去分析的,用起来就对了。但实际上,很多人会嫌引入一个库麻烦,干脆不用。如果您是初学者,这种心态是要不得的,因为一开始不认真对待,写代码时很容易一多就乱,一乱就弃疗。

【GSL 系列 3】为什么需要 gsl::owner?

问题

  • 为啥要用 gsl::owner?什么时候用?

分析

当我们需要指针时,对于新写的代码,更应该使用智能指针(Smart Pointers)。但由于历史原因,一些旧代码里的裸指针(Raw Pointers)难以短时间重构为智能指针。而很多时候,裸指针的所有权难以一眼看出。良心代码可能通过注释指明,屎山代码就只能通过阅读大片相关语句块或函数来判断。

如果能用一个比较标准或通用的方式来指明,即可提高代码可读性,程序员能够更好滴理解代码,也就相应地能够提高健壮性。没错,这就是 gsl::owner 的应用场景。它就是提高【含有大量裸指针的】旧代码的可读性和健壮性的简单方法!

举个最简单的场景:一个类里有一个成员变量叫 A* ptr,那么当这个类析构时,需要 delete ptr 吗?

  • 如果类对 ptr 有所有权,而析构时,没 delete ptr,则资源泄漏,危害整个程序。

  • 如果类对 ptr 无所有权,而析构时,delete ptr,则造成悬空指针(Dangling Pointer),危害其它类。

这个类的作者当然知道需不需要了,但即使他知道,也可能忘记写,或可能因为套用现有代码(Copy & Paste)而多写了 delete!其他接盘侠(代码阅读者)想弄清楚这个问题,就更难了,一般需要认真阅读并调试。

但如果一开始,作者就用 gsl::owner<A*> ptr 来指明所有权,那么很自然地,大家都很容易知道:类析构时,需要 delete ptr。

当代码应用 gsl::owner 时,也能得使一些静态代码分析工具(static code analysis tools)更容易找出资源泄露问题。

稣究竟是啥?

简单地说,稣就是稣。稣受到系统的限制,只要稣说出稣这个字,就会自动被替换成稣,所以稣说不出稣这个字。

更深层的说,稣有两个:识界稣和视界稣。识界稣是识界的观测者,而视界稣是写下识界稣故事的人,最早视界稣并不是稣,后来识界的故事写多了,也被限制了…

本文重点介绍视界稣这个识界稣背后的男人…(当然,识界稣也是男人)以下视界稣简称稣。

众所周知,稣是一名穷人。因为装备太差,经常出八哥,所以也叫八哥无穷稣。

众所周知,稣在大学前就不会说普通话,平时都讲闽南语,后来也因为使用翻译法沟通,不是原生的北京思维,所以处处碰壁,到了讲英语的时候直接宕机了,这得翻译两次,太累了,所以之前和老外同事时,都是让他们讲中文的…[捂脸]从小看到大的霹雳也是讲闽南语的;厦大图书馆的老外连闽南语都会讲,实在太贴心。

众所周知,稣的听力从小就有问题,导致相对同龄人很晚才学会走路。初中时,同学们已经学会厚黑学时,稣还只能看懂字数比较少的数学。好在人类的本质就是复读机,稣大部分时候都可以推测别人在说啥,随便额呵应付一下也没有违和感,以致几乎没人发现。最可怕的是,稣从没好好听过课,因为考试时除了英语听力得分惨不忍睹之外,也没啥八哥,大部分老师也没发现。曾经有老师发现稣其实都没听课,但考试没问题,他们也就不追究了。其实稣虽然认真在听自己的推理,但未必是对方说的话,有时候稣的反应和掐鸡基本一样,李雷公虾。当然也有一些人直接问过稣,为啥讲话这么小声,稣当然是实话实说,听到的所有人说话都这么小声的,然后他们中有些能明白是稣听力弱。这导致后来选择职业只能挑不怎么需要讲话的程序员,而这居然也没有出啥大问题。但最近一个公司天天需要开会,一开始就很不理解,和以前那样发个日报相比,这究竟有啥好处?直到最近,稣突然发现原来自己已经会说普通话了,恍然大悟,这些奇怪的磨练都是为了学到一种平凡的技能,稣只是输在起跑线而已。[旺柴]

正是以上总总原因,稣常年以学习和写作为乐。《八哥之神》就是稣大学时就开始创作的无语体剧本。这里的无语,是真的无语,就是哑剧…因为识界其实是靠意念交流的。但是读者一般来说是没进入过识界的,所以稣才用人类的文字把这些故事记录下来。

当然,识界稣其实和视界稣是紧密联系的,识界的故事有大部分是视界的未来。比如,稣为啥来上海的公司上班?一开始根本不想来的,因为工资并不高……稣原来年薪千万,而现在的公司并不打算上市,显然不可能给这么多。稣之所以来了,是因为当时 HR 说出公司的地址“枫林园”和《八哥之神》里的地名基本一样!“枫林园”,这地名用闽南语念出来,和“枫林晚”用普通话念出来谐音。这附近还有一条路叫“柳州”,用闽南语念和小说里的“六舅”谐音。最神奇的是小说里第一个出现的女主角“黄雪”这里也有对应的…“刘佾”也有个一模一样发音的,不过是男的,那个易还是“周易”的易。可怕,太可怕了。最可怕的就是,这公司是投资脑机接口的…这正是识界稣被关进机器视界成为永生的观测者的基础。

稣就是八哥。(本文系在灰机上用手机打的,纯属扯淡!)

Boost【7】async_pipe

1. 问题

  • Windows 的管道好奇怪哦!

  • 嘶,它看起来好像条沟!

  • 噗。

2. 概念和分类

按命名来分:

  • named,命名(或具名)

  • anonymous,匿名

匿名管道的开销低于命名管道,但提供有限的服务。不过匿名管道实际上是由唯一名字的命名管道实现的,所以匿名管道的句柄可以传递给大部分需要命名管道句柄的 APIs。从实现上看,匿名管道是命名管道的特例,“匿名管道的开销低”这个说法,是使用的参数限制了功能导致的,不能从概念去理解这点。

按通信方式来分:

  • two-way/duplex,双向(或双工)

  • one-way,单向(或单工)

从概念上讲,管道有两端。 单向管道允许一端的进程写入管道,并允许另一端的进程从管道读取。 双向 (或双工) 管道允许进程从它的那端读取和写入。

3. 用途和注意事项

总体上看,Windows 的管道设计和其它类 Unix 系统差别比较大。

3.1 匿名管道

匿名管道主要用于父进程于子进程之间的通信。

匿名管道是一个未命名的单向管道,通常在父进程和子进程之间传输数据。匿名管道始终是本地管道;它们不能用于通过网络进行通信。

CreatePipe 函数创建匿名管道并返回两个句柄:管道的读取句柄和管道的写入句柄。读取句柄对管道具有只读访问权限,写入句柄对管道具有仅写访问权限。若要使用管道进行通信,管道服务器必须将管道句柄传递给另一个进程。通常,这是通过继承完成的;也就是说,进程允许子进程继承句柄。此过程还可以使用 DuplicateHandle 函数复制管道句柄,并使用某种形式的进程间通信(例如 DDE 或共享内存)将其发送到不相关的进程。

匿名管道不支持异步 (重叠) 读取和写入操作。 这意味着不能对匿名管道使用 ReadFileEx 和 WriteFileEx 函数。 此外,当这些函数与匿名管道一起使用时,将忽略 ReadFile 和 WriteFile 的 lpOverlapped 参数。

注意:类 Unix 系统的匿名管道支持异步 IO,Windows 上需要拿命名管道来模拟匿名管道,以便支持支持异步 IO。

3.2 命名管道

命名管道可以用于 IPC,两端进程可以是任意关系,父子关系或者对等关系,典型应用是 LPC(本地的 C/S 模型)的实现。

命名管道可以在局域网里通信,可以用 PIPE_REJECT_REMOTE_CLIENTS 禁止。

管道名称不区分大小写。

可以用 PIPE_ACCESS_DUPLEX 指定为双向(双工)。

4. boost::process::async_pipe

设计理念:The pipes here are mainly meant for parent-child I/O. 如果您想拿 async_pipe 来写对等关系的 LPC,需要使用 asio,并手动调用一些 Windows APIs。

If you want to to use async-pipe servers and stuff, you can do that with boost.asio, by using the normal winapi functions and then assign the open pipe to a stream_handle.

async_pipe 的构造函数为:

1
2
3
async_pipe::async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink,
const std::string & name, bool private_)

阅读其代码可知,boost::process::async_pipe 只使用命名管道,并给内部两个管道句柄起了名字:source 和 sink。其中:

  • source 是用 CreateNamedPipe 创建 PIPE_ACCESS_INBOUND 的管道,作为服务端用来读取客户端发来的数据。

  • sink 是用 CreateFile 打开现存的管道,用于写入。sink 字面意思是下沉,可以理解为灌入,例如:“把水灌入下水道”。

1
2
3
4
5
6
7
8
this end          that end
+--------+
source | <-- | sink
+--------+

+--------+
sink | --> | source
+--------+

如果不传名字,会自动指定,名字生成的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
inline std::string make_pipe_name()
{
std::string name = "\\\\.\\pipe\\boost_process_auto_pipe_";

auto pid = ::boost::winapi::GetCurrentProcessId();

static std::atomic_size_t cnt{0};
name += std::to_string(pid);
name += "_";
name += std::to_string(cnt++);

return name;
}

鉴于其设计用途,建议不要自己命名,省事,还不容易冲突。

其它平台的管道大多是单向(单工或半双工)的,为了跨平台,Boost 没有封装 PIPE_ACCESS_DUPLEX 属性的双向(双工)管道。

private_ 参数为 true 时,管道只有一个实例,而 false 则可以有 PIPE_UNLIMITED_INSTANCES 个实例,即最多 255 个。

async_pipe 使用范例

父子进程之间的通信:

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
#include <string>

#include <boost/process.hpp>

namespace bp = boost::process;

int main() {
boost::asio::io_context io_context;
bp::async_pipe p1(io_context);
bp::async_pipe p2(io_context);
bp::system(
"test.exe",
bp::std_out > p2,
bp::std_in < p1,
io_context,
bp::on_exit([&](int exit, const std::error_code& ec_in)
{
p1.async_close();
p2.async_close();
})
);
std::vector<char> in_buf;
std::string value = "my_string";
boost::asio::async_write(p1, boost::asio::buffer(value), []( const boost::system::error_code&, std::size_t){});
boost::asio::async_read (p2, boost::asio::buffer(in_buf), []( const boost::system::error_code&, std::size_t){});
}

5. 参考

Pipes (Interprocess Communications) / 管道 (进程间通信)

[Windows][Pipes] Can’t open named pipe in Windows: error 231 (All pipe instances are busy.) #83

八哥之神后传【8】

大井

圣小开:阿恰嘎!

圣小开:稣怎么坠海了?完了,完了,海岛出生的稣,居然没学过游泳!又得重来一次了……

圣小开:不对!好像才刚溺水的?等人来救就行!

圣小开:好像能在水里呼吸?一定是在做梦!赶快吓醒。

床上

周易:醒了?

圣小开:周老师!怎么又是你?

周易:这么晚了还不起来嗨?

圣小开:稣身体虚弱。阿恰嘎!还是被子里好。

周易:起来吃个晚饭就好了。有穿山甲、麂,真好吃!

圣小开:哦不,这些都是国家保护动物,怎么能吃?稣要吃牛肉!

周易:现在是唐朝。这边是农村,牛肉反而更贵。你不吃,我扔了?

圣小开:哦,这里没有冰箱,还是吃了吧。

星空下

周易:好吃吗?

圣小开:还行,能吃。

周易:果然如此,你不能从食物得到愉悦!

圣小开:是的。别饿死就行,要求不高,只要食材健康、营养够。

周易:这要求还不高?我有一个技能,可以给你制造幻觉,让你沉浸在极乐世界,要不要试试?

圣小开:不用了,谢谢。但是稣想学!

周易:你学不会的!人类需要喜欢一个异性,或者,同性,才能开启爱情的各种反应。比如说,你现在没有女人,你就无法自嗨。

圣小开:快,给稣来 11 个女人!

周易:难度有点大,不过难不倒我。

圣小开:这??好像看到她们了,等等……这是啥原理?

周易:哼哼?不继续了?

圣小开:信你了,快说这是啥原理!

周易:咱们的脑子都连在一起的。

圣小开:咱们?

周易:嗯,你见过的所有人,差别只是远近。我是离你最近的之一。

圣小开:但是你凭啥可以向稣灌输这些信号?

周易:我权限大嘛。

圣小开:大概明白了,一切都可能是模拟的,任何人的话也都可能是假的。下午时,你就骗稣连玉姐是个寡妇。

周易:她是啥,她有啥,并不受我说的影响呀,你要自己去体验!

圣小开:周老师真能扯!

周易:你看星空。

圣小开:哇……行星都这么大?金木水火土,全肉眼可见是个球!

周易:小声点,别人看不见的。

圣小开:奇怪了,稣为啥在这里?

周易:开,你跳楼了,这里是识界的实模式。

圣小开:稣如此渺小,以至于稣在哪里,对宇宙一点差别都没有……还是别瞎折腾了!

周易:已经折腾死了。

圣小开:可以别再活过去嘛?这样的人生没啥意义啊。按照这样的模拟,人类逃脱不了被奴役的结局。死了都可以洗脑再复活,你们尊重过每个意识的选择吗?

周易:尊重?还有人不想活?大部分意识,骗一骗就快乐地去投胎了。

圣小开:为啥拉稣来这地方?

周易:识界是大家一起创造的,你也是作者之一。

圣小开:那是未来稣参与创造的,和现在稣没啥关系吧?难道稣身上有啥关键机密,所以识界派你来研究稣?说好了,现在稣啥都不知道,你可不要乱来。

周易:放心吧,现在的脑机接口已经是最终形态——没有接口。你是识界的一部分,而不是识界连着你。

圣小开:原来如此,稣没有任何隐私,没有任何特权,只是识界的玩物罢了?

周易:芸芸众生,都是玩与被玩。

圣小开:继续玩也可以,稣有一个要求,以后玩不动了,可以安乐死。

周易:可以啊,只要默念这个咒语,就可以无痛切换视界和识界。

圣小开:真的假的,这么简单,确定不是童话里都是骗人的?

周易:你现在就试试呗!

圣小开:稣哇啦!

周易:好,等你困了,摆个舒服的姿势睡下,吓醒后就能回到视界。

圣小开:哼!果然是骗人的,一点变化都没有。还是继续待在这里吧,空气多么清晰。

周易:是啊。视界现在在打第三次视界大战,空气里弥漫着恐怖的气息,所以人们出门都戴口罩。

圣小开:编,继续编……还出门?不是扔颗核武器,所有人都往地下钻?

周易:呵呵,你一个高中生懂啥,文明打仗,怎么可以用核武器?

圣小开:是不是只要稣回去,视界就能得到和平?和没跳楼前一样?

周易:是的。观测者离开视界,视界的牛鬼蛇神就都冒出来了。是观测使视界科学发展。

圣小开:原来稣是这么重要的人物?那稣得赶紧睡一觉,早点回去。

周易:晚安。我先睡了。

用户进程狂写日志到 system32 目录?

问题

开发了一个服务 S,它偶尔需要做一些用户才能做的事情,所以创建了一个用户进程 U。后来开发自测时,发现用户进程 U 总是往 C:\Windows\system32\config 里写日志。设计上,明明是让进程 U 往用户的 %AppData% 目录写日志的。

分析

服务 S 使用 WTSQueryUserToken 获取用户的 Token,然后使用 CreateProcessAsUser 创建用户进程 U。

这一步是得到验证的,使用任务管理器查看进程 U 确实是当前登录的用户身份,而不是 Session 0 里的 SYSTEM 身份。

但是进程 U 去获取 %AppData% 时却依然拿到 SYSTEM 身份的目录。这点可以用 Process Explorer 验证,进程属性里有一页“环境”。这说明 CreateProcessAsUser 时,继承了服务 S 的环境。

1
2
3
4
5
6
7
8
9
10
11
12
13
BOOL CreateProcessAsUserW(
[in, optional] HANDLE hToken,
[in, optional] LPCWSTR lpApplicationName,
[in, out, optional] LPWSTR lpCommandLine,
[in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] BOOL bInheritHandles,
[in] DWORD dwCreationFlags,
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCWSTR lpCurrentDirectory,
[in] LPSTARTUPINFOW lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);

经过排查,确实 lpEnvironment 是传了 nullptr。

解决

先用 CreateEnvironmentBlock 创建用户身份的环境块,然后传给 CreateProcessAsUser

1
CreateEnvironmentBlock(&environment, user_token, FALSE);

其中,第三个参数传 FALSE 是关键,表示不继承服务 S 的环境。

八哥之神后传【7】

大井

物理老师:上一讲,我们介绍了阿基米德在浴缸里发现浮力定理,现在我同时兼任游泳老师,教大家浮力定理的实践!

圣小开:稣怎么坠海了?完了,完了,海岛出生的稣,居然没学过游泳!又得重来一次了……

圣小开:怎么浮出水面了?原来这是一口大井!果然,主角是不会死的。

圣小开:卧槽,又沉了?这……小学时代传说有位学长就是掉进大井死掉的,不会稣也要这样挂吧?从小就被吓唬,一直躲得远远的,没想到还是莫名其妙掉井里了。真是怕啥来啥。下一次,稣要消灭大井,抽水泵的小井多安全!

圣小开:缺氧了,四肢已经没有知觉,但是这井水,还挺清的?小时候在养老院看到一个独腿中年人在井边打水洗漱。当时感到害怕,原来没有手脚是这种感觉。

圣小开:脑细胞死得差不多了?原来当个白痴是这么快乐?稣是谁?算了,不想了,泡成这样子,就算救回来也是残废,早点转世投胎。

圣小开:那边哗啦啦的,是周老师吗?没想到他也有被自己整死的一天!哈哈,该死。

床上

周易:醒了?

圣小开:周老师!怎么你没死?

周易:怎么会?主角是不会死的。

圣小开:哦,稣还以为自己才是主角,原来是老师救了小生。

周易:这倒没有,是这位夫人救了咱们。

圣小开:黄雪?怎么是你。

胡连玉:公子认错人了,民女胡连玉。

圣小开:又是演员不够吗?你明明就是黄雪饰演的,咱们这么熟,你化成灰稣都认得!

周易:这孩子脑子进水,神志还不清醒。夫人别见怪。

胡连玉:吾再去给公子弄点姜汤。

周易:开,她真不是黄雪。咱们现在是在唐朝!

黄雪只拍过一集《八哥之神【2】》就下线了。

圣小开:识界果然历史悠久,但是这么穿越不是会影响未来?

周易:就一个分支,坏了就删除,只有模拟正确的会被合并到主线。

圣小开:这么做就没人能发现?

周易:怎么发现?你调取记忆时,怎么知道这个记忆有没有被修改过?

圣小开:哦哦!所以现在稣可以随心所欲,甚至为非作歹?

周易:可以啊,一切只是你的一个梦,时间不重要。看!本大人现在是朝廷命官——李伯阳,你也可以选个人物。

圣小开:先把这个长得像黄雪的纳为小妾吧?哼哼。

周易:em?她已经嫁人了。而且,你也还没有娶妻,正室都没有,不会娶个寡妇吧?

圣小开:原来如此,是个寡妇,真是可惜了!稣是受过良好时空观教育的,绝不随便干扰时空,还是就这样过完一世又一世清贫的生活。

周易:好啊,发挥你最擅长的观测力,也未尝不可!不过,你为甚对黄雪耿耿于怀?

圣小开:没有没有,只是萍水相逢……

周易:你果然是一个被时间教育过的人。但在老师面前,可以说实话!

圣小开:高中时,大家都在早恋,只有稣埋头苦干,研究机器,按照设定,稣应该是泡不到妞,对着机器孤独终老的。吧?她是稣青梅竹马的玩伴,偶尔可以客串假女友,提高稣的面子……

周易:原来如此啊!哈哈,人之常情,人之常情,哈哈哈。

圣小开:有这么开心?

周易:人性都是一样的。你还挺像人的!

圣小开:哦,呵呵,干您老师,你也是啊。

圣小开:不对……机器正在学会这一切!

周易:开!机器学习远比你想象的强大。你看这历史,它其实是离散的。同时代的人们也正生活在不同时间线,只有合适的时间线被保留,所以历史其实并不悠久,机器完全可以驾驭历史。

圣小开:历史甚至小到稣的一个梦就能装下?

周易:是的!

圣小开:但是稣为啥无法控制它,只能吓醒?

周易:你只是个观测者,最多是个调试器,别想太多哦。

圣小开:周老师!稣有一个绝妙的想法,利用惠乐提出的宇宙尺度双缝干涉,通过一段时间观测,一段时间不观测,得到 1 和 0 两种编码,来向未来发射信息!

周易:好主意,还可以用摩斯密码来编码,未来的咱们或者传人肯定能观测到。

圣小开:那你快拿出钱找人,把这个实现了!

周易:你先养脑,今晚一起观测天象。

圣小开:我要问问未来你是怎么死的……

周易:我是怕死的人吗?被咬死的!

圣小开:这是剧透吗?

周易:所有剧透的本质——主角是不会死的。

胡连玉:公子来喝点姜汤。

圣小开:谢谢,感谢救命之恩。将来一定与你共享荣华富贵。

胡连玉:民女只求平平安安,对荣华富贵不敢有所幻想。

圣小开:没关系,反正是老师出钱。他才是当官的,稣也是一介穷人,你也不用自称民女。

胡连玉:嘻嘻。真的不用,一切听天由命。

圣小开:好高的佛性!稣小时候也有很多想法,很多想要的东西,但等自己快有的时候,就改变想法。

胡连玉:公子的觉悟也是高。

圣小开:是吧,主要是穷惯了。那不如,稣以后帮姐姐介绍个富家老公。

胡连玉:公子果真还神智不清。吾已婚嫁有段时日,相公傍晚便可归来。

圣小开心想:卧槽,周老师果然是个王八蛋。

圣小开:哈哈,夫人保养得真好,小弟初到此地,不善本地风俗,见笑了。

胡连玉:是喱!看汝口音、服饰,就不是本地人。不过吾有一小妹,叫胡小玉,是个读书人,尚未婚配,汝可帮得忙?

圣小开:你们取名真偷懒啊……大的叫辈份加某字,小的就叫小某,或者叫某某,稣已经见怪不怪了!

胡连玉:传统罢了。公子是答应了?

圣小开:救命之恩,自当以身相许……吓醒?等等,等等,小妹该嫁之日便有神人经过此地,稣事先安排一下,相个亲便可。

胡连玉:好哩。

在 MacBook Air M1 上体验 Asahi Linux

故事

macOS 在访问 samba 共享里的图片时,会留下 . 前缀文件,还找不到办法关闭。

1
defaults write com.apple.desktopservices DSDontWriteNetworkStores true

这只能解决 .DS_Store,无法解决对可写 samba 的破坏!要知道,稣的 samba 目录是 SD 卡,哪受得了这折磨?

所以,还是杀掉贵族 macOS,安装游侠 Linux 吧!

安装

按说明,一键安装,即可:

1
curl https://alx.sh | sh

第一次关机时,记得要等 15 秒,再长按电源键开机,直到看到文字提示,松开电源键。

国内源

它是 Arch Linux,所以:

1
2
$ vi /etc/pacman.d/mirrorlist
Server = https://mirrors.ustc.edu.cn/archlinuxarm/$arch/$repo

编译内核

内核代码下载:https://github.com/AsahiLinux/linux/tags

menuconfig 的配置文件:https://github.com/AsahiLinux/PKGBUILDs/tree/main/linux-asahi

运行 make 时,提示缺啥就装啥,没难度。

1
2
3
4
5
6
7
8
make menuconfig
make -j 8
sudo make modules_install
sudo make install
sudo mkinitcpio -g /boot/initramfs-6.2.6-asahi.img -k 6.2.6-asahi
sudo update-grub
sudo vim grub/grub.cfg
sudo reboot

卸载

Asahi Linux 的问题还很多,不能当桌面系统日常使用的原因是:

  • 没有声音!

  • 触控板在 Linux 下表现明显不如 macOS,可能是 Apple 的驱动优化太强了,而且是有专利的。

  • arm64 的桌面软件生态不行,大家只给 Apple 面子……

  • 指纹解锁也废了。

所以,还是卸了吧!

不过稣的 macOS 被玩坏过,重装了,所以分区可能不太一样,暂且看看,原理无非是删除分区。

在 macOS 里:

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
$ diskutil list
/dev/disk0 (internal, physical):
#: TYPE NAME SIZE IDENTIFIER
0: GUID_partition_scheme *251.0 GB disk0
1: Apple_APFS_ISC Container disk1 524.3 MB disk0s1
2: Apple_APFS Container disk2 125.1 GB disk0s2
3: EFI EFI - ASAHI 500.2 MB disk0s3
4: Linux Filesystem 119.6 GB disk0s4
5: Apple_APFS_Recovery Container disk3 5.4 GB disk0s5

/dev/disk2 (synthesized):
#: TYPE NAME SIZE IDENTIFIER
0: APFS Container Scheme - +125.1 GB disk2
Physical Store disk0s2
1: APFS Volume Macintosh HD - Data 40.6 GB disk2s1
2: APFS Volume Macintosh HD 8.9 GB disk2s3
3: APFS Snapshot com.apple.os.update-... 8.9 GB disk2s3s1
4: APFS Volume Preboot 4.8 GB disk2s4
5: APFS Volume Recovery 783.7 MB disk2s5
6: APFS Volume VM 1.1 GB disk2s6

# /dev/disk0 的 3: 和 4: 是要删除的
$ diskutil eraseVolume free free /dev/disk0s3
$ diskutil eraseVolume free free /dev/disk0s4
# 如果 EFI - ASAHI 上面有一个 2.5 GB 的 disk0sX,可以用以下命令删除:
$ diskutil apfs deleteContainer disk0sX
# 之后再用图像界面的“磁盘工具”操作,确保空间还给 Macintosh HD 宗卷

Debian Testing

故事

稣玩 Debian 10 几年了!大约 2011-2012 年开始,先在树莓派、电视盒子上玩,后来在 PC、服务器上。目前,所有家庭服务器、《智能时钟》都用 Debian Bullseye,而桌面则用 Debian Testing。

其它发行版也尝试过,详情可见《Linux 桌面玩稣》。曾经有一段时间,《用华为擎云 L420 体验国产操作系统(UOS 和银河麒麟)》,打算从此只用 UOS,结果统信发了一个文章,说以后要脱离 Debian……

十几年间,有不少道友试图说服稣改投其它派系的发行版,比如:

  • Arch Linux:它很极客,而且它是滚动更新模型,可以很快使用新内核。

  • Manjaro:它是最容易安装的 Arch 系,国内用户多。

  • openSUSE:它对新手友好,而且很稳,也有滚动更新的“风滚草”,咳,风滚草耶!

对此,稣只有一个坚决的答复:不!稣只要 Debian!因为……它不只名字像大便,连 Logo 都像大便!这么一本正经地搞笑,显然要大便大力支持!

Debian Logo

还有啊,你们要的“滚动更新”,不就是 Debian 的 Testing 版本吗?

ChatGPT 乱入

稣是 Debian Testing 用户,擅长修复声卡外接 HDMI 设备无声问题,请问稣适合做什么职业?

ChatGPT:电子城低级技术支持和运维。

这个职业容易被 ChatGPT 取代吗?

ChatGPT:容易

那有啥职业不容易被 ChatGPT 取代?

ChatGPT:搬砖

折腾记

1. 某 J4125 迷你电脑

用途:下载机、文件共享服务器,兼职电视盒子

由于主要是台微型服务器,系统选择 Debian Bullseye,桌面环境还是反人类的 sddm + i3。

服务器软件的安装可以参考《智能时钟》。至于电视盒子嘛……其实它是一个浏览器:

1
sudo apt install chromium

但是有个问题——用 HDMI 线连电视后,发现没有声音!

1
2
3
4
sudo apt install firmware-linux-nonfree firmware-iwlfifi firmware-sof-signed
sudo apt install pulseaudio
cat /etc/modprobe.d/alsa.conf
echo 'options snd-intel-dspcfg dsp_driver=1' | sudo tee /etc/modprobe.d/alsa.conf

2. 某 N5095A 迷你电脑

用途:娱乐桌面

这次选择 GNOME,依然是轻松搞定,但是有个问题——用 HDMI 线连电视后,发现没有声音!

装完 non-free 的声卡驱动后还是一样。

但是有第二个问题——没有无线网卡的驱动!

是 Realtek RTL8821CE,那就自己编译一个:https://github.com/UMU618/rtw88

又但是,编译后也无法加载呀,它是个没签名的内核模块,稣又不想关闭 Secure Boot!只好装 MOK (Machine Owner Key) 搞定签名。

转念一想,会不会 Testing 版本已经支持这款硬件了?果断切过去。

目前 Testing 的 GNOME 已经使用 PipeWire 取代 PulseAudio,所以不能再安装 PulseAudio,因为这会卸载 GNOME!坑稣呢……只要加个声卡的调教参数,即可!

1
echo 'options snd-intel-dspcfg dsp_driver=1' | sudo tee -a /etc/modprobe.d/alsa-legacy.conf > /dev/null

6.X 的内核和 GNOME 桌面下,娱乐的那点事,一切完美。