前言
这个是一个用于记录学习资料的博客,使用mdbook把markdown渲染成静态网页,使用github Actions流水线部署到Github Pages。
mdbook是真正的简单好用,最喜欢的功能是在SUMMARY.md内创建目录,会自动创建文件夹,而且SUMMARY.md可以使用//
注释掉不想发布的页面。
因此第一篇文章将分享如何mdbook部署笔记。
交流可以到该项目提issue。
mdbook命令
mdbook的主要命令就是初始工程和启动服务。
init
> mdbook init -h
mdbook.exe-init v0.4.21
Creates the boilerplate structure and files for a new book
USAGE:
mdbook.exe init [OPTIONS] [dir]
ARGS:
<dir> Directory to create the book in
(Defaults to the Current Directory when omitted)
OPTIONS:
--force Skips confirmation prompts
-h, --help Print help information
--ignore <ignore> Creates a VCS ignore file (i.e. .gitignore) [possible values: none,
git]
--theme Copies the default theme into your source folder
--title <title> Sets the book title
-V, --version Print version information
serve
> mdbook serve -h
mdbook.exe-serve v0.4.21
Serves a book at http://localhost:3000, and rebuilds it on changes
USAGE:
mdbook.exe serve [OPTIONS] [dir]
ARGS:
<dir> Root directory for the book
(Defaults to the Current Directory when omitted)
OPTIONS:
-d, --dest-dir <dest-dir> Output directory for the book
Relative paths are interpreted relative to the book's root
directory.
If omitted, mdBook uses build.build-dir from book.toml or defaults
to `./book`.
-h, --help Print help information
-n, --hostname <hostname> Hostname to listen on for HTTP connections [default: localhost]
-o, --open Opens the compiled book in a web browser
-p, --port <port> Port to use for HTTP connections [default: 3000]
-V, --version Print version information
1.初始化工程
mkdir docs && cd docs
mdbook init . --title "my book"
2.启用服务,默认端口是3000,--open会自动打开默认浏览器。
mdbook serve . --open
3.现在可以通过在编辑src下的SUMMARY.md中新增章节,新增条目后,会自动创建文件,同时更新网页目录。

serve自动将markdown渲染输出到book目录,因此.gitignore
文件的book,表示忽略book目录内的修改,防止触发build。
参考:https://rust-lang.github.io/mdBook/index.html
github pages
github pages 支持静态网页,我们需要把我们渲染后的mdbook上传到github pages仓库。虽然简单粗暴,但有几个完美主义者不能接受的缺点。
- 手动build渲染生成的静态网页再push,diff肯定会很多,看起来不舒服。
- 本地修改的markdown丢失,通过静态网页恢复很麻烦。
因此,我们需要CICD流水线帮助我们build & deploy,我们只管提交md源代码即可。 github的CICD工具很多,当然肯定是他们自亲儿子Actions最好,点击仓库中的Actions选项就能看到流水线。
gitlab里叫pipelines,github叫workflows,我们只需要在当前mdbook工程的 .github/workflows
下创建yaml格式的流水线控制文件即可。
mkdir -p .github/workflows
vim .github/workflows/gh-pages.yml
我们新建的gh-pages.yml
内容:
name: GitHub Pages Site Build and Deploy workflow
on:
# 触发流水线的事件,推送或者合并
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build-and-deploy:
# 使用构建镜像
runs-on: ubuntu-latest
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
# clone代码,使用checkout这个action,不带@表示使用最新版本,官方建议带。
steps:
- name: Checkout
uses: actions/checkout@v2
# 构建代码,相当于使用别人做的mdbook docker
- name: Build and Deploy
uses: peaceiris/actions-mdbook@v1
with:
mdbook-version: 'latest'
# 构建代码
- run: mdbook build
# 部署静态页面
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
if: ${{ github.ref == 'refs/heads/main' }}
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_branch: gh-pages
publish_dir: ./book
在提交代码之前需要:
1.创建ssh密钥对
密钥对生成在当前目录下,千万不要在工程目录下创建,否则不小心提交上去就悲剧了。
cd #切换到用户目录去创建
git config --global user.name yourname
git config --global user.email yourname@gmail.com
ssh-keygen -t rsa -b 4096 -C "$(git config user.email)" -f gh-pages -N ""
2.github上创建项目并配置
-
创建项目名称:your-github-name.github.io
-
仓库的Settings里的Deploy Keys项目添加key,
title
为ACTIONS_DEPLOY_KEY
,Key
填入公钥文件gh-pages.pub
的内容,勾选Allow write access
;在Secrets下的Actions内添加Secrets,
Name
为ACTIONS_DEPLOY_KEY
,Secrets
填入私钥文件gh-pages
的内容。
3.推送本地项目
# 初始化当前mdbook工程,并将本地项目的远端设置为新建的git仓库地址
git init .
git add *
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:errorcode7/errorcode7.github.io.git
# push前,保证本地.ssh下的公钥已经添加到github账户Settings的SSH keys
git push -u origin main
4.检查部署页面
提交成功后点击仓库里的Actions,查看流水线构建情况。
提交代码后会触发构建流水线,生成的静态网页会被自动提交到gh-pages
分支,触发静态网页部署的流水线,因此每次提交都有两个流水线,源码构建与page部署,其中pages build and deployment
是部署到github.io的流水线。

注意:如果页面404,到项目的Settings->Pages下查看Pages站点的来源是那个分支,可以手动切换到gh-pages
分支,会重新触发Action,要等部署完才生效。

当前pages工程的仓库地址:https://github.com/errorcode7/errorcode7.github.io
参考:https://github.com/marketplace/actions/mdbook-action
3D渲染基本概念
- 顶点(vertex),描述物体在三维坐标中的向量,一个三角面有三个点,每个顶点有一组三维坐标项链[x,y,z],物体越复杂,构成的顶点则越多。物体除了顶点还有纹理坐标,法线,顶点色等数据组成,把这一组数据统称vertex buffer,存储数据的格式有很多种。
- index buffer,物体的表面需要上色,三个顶点是构成一个面的最小单元,记录一组顶点下标的数组,叫做index buffer。当我们绘制多边形的时候,传入的是顶点的索引,而非索引数组,可提高代码效率。比如我们绘制四边形的时候,需要传入两个三角形的顶点,当我们用索引记录的时候,只需要传入包含6个顶点的索引的index buffer即可。
- 纹理(Texture),自然界中重复出现的颜色叫做纹理,多种重复出现的纹理可以组合继续重复出现,构成更大的纹理,在二维平面中就是一张图片。顶点的纹理坐标记录着顶点在纹理二维平面中的坐标,3维空间中的顶点通过这个纹理坐标映射到在纹理数据中的坐标,使得每个单元都有对应的颜色。
- 光栅化(rasterization),三角形在屏幕坐标中是由N个正方形像素构成,用颜色填充三角形覆盖范围内的像素的过程叫做光栅化。这个固定的步骤是可以固定计算单元实现,叫做rasterizer。在填充之前,需要将3D空间中的三角形变换为屏幕中的2D三角形。最终的颜色是由材质,纹理,光源等经过就算得出,类似函数y=ax1+bx2+cx3一样多个参数输出,控制最终的输出。(光栅化这个翻译,就不能信达雅吗?)
- 着色器(shader),shade本意是阴影,shader最初是用计算光照和阴影的,上色的过程本质就是一个计算的过程,每一个计算的函数也叫做一个shader。因此shader并不只是上色,只要有变换的地方都需要计算,变换千差万别,计算函数也千差万别,因此这部分是可编程的,所谓的shader编程本质就是函数编程。处理顶点的叫vertex shader,处理像素的叫pixel shader,不同的shader出现在流水线(管线)的不同阶段。
- 管线(pipline),将原始数据,像工厂流水线一样,经过各种单元处理,最终生成可以显示输出的帧(framebuffer)对象。
- surface,这是egl的概念,像是一个可以修改的图层或画布,对内管理着它拥有的framebuffer,对外(窗口)表示自己有显示能力,不同操作系统的窗口管理器产生的窗口都可以和surface绑定,让它提供显示能力,不用关心它一个还是多个buffer实现,它可以在屏幕内,也可在以屏幕外。结合Wayland的描述,它可以和背景绑定,窗口绑定,光标绑定。OpenGL只负责将数据渲染成帧,并不负责输出到屏幕。输出屏幕的工作叫做送显示,属于窗口管理器的活儿。早年显卡没有3D渲染加速时候的主要工作就是送显,这个部件叫做
Display Controller
,kms驱动就是为他服务。操作系统的核心就是管理硬件,抽象成资源,被软件复用,多个应用程序都要输出则需要对显卡复用,首先驱动层面就要支持,其次系统层面要统一管理。渲染产生的帧通过surface被窗口记录,窗口管理器将不同窗口进程的记录的帧通知合成器统一合成,合成器把背景,多个窗口,光标交给硬件合成为一帧,然后送显部件送给显示器显示。全屏游戏独占屏幕,应用显示的帧几乎就是最终送显的帧,手机app这类占用大部分屏幕且状态栏基本没有变化的场景,合成的成本很低。
OpenGL ES3 管线流水线中,API箭头表示可以输入的部分。

vertex shader 实现代码
#version 300 es // OpenGL ES版本信息
uniform mat4 u_mvpMatrix; // 同一变量u_mvpMatrix,它存储组合的模型视图和投影矩阵。
// 描述顶点着色器的输入
in vec4 a_postion; // 输入顶点位置属性
in vec4 a_color; // 输入顶点颜色属性
out vec4 v_color; // 存储描述每个顶点颜色的顶点着色器输出
void main(){ // 主函数
v_color = a_color; // 读入顶点属性输入a_color,并将其写入顶点输出颜色v_color
gl_Position = u_mvpMatrix * a_postion // gl_Position是自动生成的,将变换后的顶点位置写入gl_Position输出
}
shader的本质就是y=ax1+bx2+cx3这样的矩阵计算,因此,输出入包含变和不变量两个部分,以u_mvpMatrix代表的是[a,b,c]这样的不变部分;a_postion,a_color这类顶点数据则代表做x1,x2这类变化的部分。
https://www.bilibili.com/video/BV1P44y1V7bu/ 《上帝视角看GPU(1):图形流水线基础》 https://vulkan-tutorial.com/Vertex_buffers/Vertex_input_description 《vulkan教程》 https://blog.csdn.net/xzben/article/details/124107260 《OpenGL 之Texture》 https://zhuanlan.zhihu.com/p/381327745 《【Learn OpenGL笔记】纹理(Texture)》 https://zhuanlan.zhihu.com/p/144332091 《计算机图形学七:纹理映射(Texture Mapping)及Mipmap技术》 https://www.intel.com/content/dam/develop/external/us/en/documents/the-architecture-of-intel-processor-graphics-gen11-r1new.pdf 《Intel核显Display Controller》
x11
x11是C/S模型,每个主机可以启动多个xserver作为服务器,每个服务器开启一个端口,供客户端连接,每个服务器可以有多个screen(显示器),因此服务地址的格式为DISPLAY=host:port.screen_number
,由于默认端口为6000起步,真实tcp/ip端口为6000+port
。
每个screen可以上可以创建多个窗口。
xlib
xlib是协议的c语言接口。
GraphicsContext
绘图操作需要控制数据,通过数据结构保存这些复杂参数,传递给Server。
xcb
X协议的C语言绑定,相比xlib,占用空间小,延迟低,多线程,可扩展等特性。
https://www.x.org/wiki/guide/xlib-and-xcb/ https://www.x.org/releases/current/doc/libxcb/tutorial/index.html
SPDX
SPDX(Software Package Data Exchange)是一种文件格式,用于记录有关分发给定计算机软件的软件许可证的信息。SPDX 是由 SPDX 工作组编写的,该工作组代表了 20 多个不同的组织,由 Linux 基金会所支持。
简单的说,就是简化授权说明。
reuse
该工具用于在文件头添加SPDX格式的版权与license。
官方用例,init初始reuse,download下载license,addheader添加license到文件头,addheader
会根据文件类型自动添加注释,最后reuse lint检测。

#新建项目
git clone -b noncompliant https://github.com/fsfe/reuse-example.git
#初始化,生成文件`.reuse/dep5`
pip3 install reuse
cd reuse-example && reuse init
#下载协议放到LICENSES/GPL-3.0-or-later.txt,reuse download --all 下载所有
reuse download GPL-3.0-or-later CC0-1.0
#添加所有文件,不想添加的文件加入.gitignore
reuse addheader --copyright="Jane Doe <jane@example.com>" --license="GPL-3.0-or-later" src/main.c Makefile README.md
reuse addheader --copyright="Jane Doe <jane@example.com>" --license="GPL-3.0-or-later" --force-dot-license img/cat.jpg img/dog.jpg
reuse addheader --copyright="Jane Doe <jane@example.com>" --license="CC0-1.0" .gitignore
#检测合规,会列举未授权的文件,最终要看到`Congratulations!`才行。
reuse lint
开源协议分类

参考:https://reuse.software/tutorial/
源码编译zig
添加llvm18的源
zig要求这个版本
# uos v20
deb http://apt.llvm.org/buster/ llvm-toolchain-buster main
deb-src http://apt.llvm.org/buster/ llvm-toolchain-buster main
# 18
deb http://apt.llvm.org/buster/ llvm-toolchain-buster-18 main
deb-src http://apt.llvm.org/buster/ llvm-toolchain-buster-18 main
# 19
deb http://apt.llvm.org/buster/ llvm-toolchain-buster-19 main
deb-src http://apt.llvm.org/buster/ llvm-toolchain-buster-19 main
# deepin v23
deb http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm main
deb-src http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm main
# 18
deb http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm-18 main
deb-src http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm-18 main
# 19
deb http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm-19 main
deb-src http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm-19 main
https://apt.llvm.org/
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
https://apt.llvm.org/
配置编译环境
sudo apt install -y build-essential cmake clang-18 libclang-18-dev libclang-cpp18-dev llvm-18 llvm-18-dev lld-18 liblld-18-dev libpolly-18-dev libllvm18
alias llvm-config=/lib/llvm-18/bin/llvm-config
llvm-config --cxxflags --ldflags --system-libs --libs core
https://github.com/ziglang/zig/issues/419
下载zig源码编译
在build目录构建,方便删除
git clone https://mirror.ghproxy.com/https://github.com/ziglang/zig.git
cd zig
mkdir build
cd build
cmake .. -DCMAKE_PREFIX_PATH=/usr/lib/llvm-18 -DZIG_STATIC_LLVM=ON
make
https://github.com/ziglang/zig/wiki/Building-Zig-From-Source
以上步骤为了验证是否能正常打包。
构建debian包
准备环境
sudo apt install dh-make
制作debian文件
生成debian目录
#移除编译build目录,否则--createorig参数创建源码包会包含这些
rm -rf build
#获取最新tag信息,用于作为debian版本
ver=$(git describe --tags --abbrev=0)
git checkout $ver
dh_make -p zig_$ver -s -y --createorig
rm -f debian/*.ex
编辑debian内的文件,关键是添加Build-Depends,方便apt build-dep .
自动下载打包依赖。
如果有修改,需要dch -i
命令添加changelog
debian/control文件内容。
Source: zig
Section: devel
Priority: optional
Maintainer: errorcode7 <errorcode7@qq.com>
Build-Depends: debhelper (>= 11),dh-make,dpkg-dev,build-essential,cmake,clang-18,libclang-18-dev,libclang-cpp18-dev,llvm-18,llvm-18-dev,lld-18,liblld-18-dev,libpolly-18-dev,libllvm18
Standards-Version: 4.1.3
Homepage: https://ziglang.org/
Vcs-Git: https://github.com/ziglang/zig
Package: zig
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Zig is a general-purpose programming language and toolchain for maintaining robust, optimal and reusable software.
https://github.com/errorcode7/zig/tree/master/debian
dpkg-buildpackage打包
# 因为有Cmake文件,直接构建即可
rm -rf .zig-cache/
dpkg-buildpackage -uc -us -tc
可能会提示gpg签名失败,不要紧,已经打包好了。
dpkg -c ../zig_*.deb