0%

省流版

  1. claude-mem 负责全部将细节注意记住,跨会话记忆存储当前 top 方案
  2. magic-context 负责会话内上下文裁剪,和近期记忆保存。记忆方面不强,但是会话内保持任务目标和遵守规范行为进行进行上下文裁剪压缩
  3. Strict-Doc 负责记录固化的项目文档文件,记忆文件。主要是方便人类进行阅读查看
  4. AGENTS.md 添加一小段 tail 来规范行为
  5. 自制 load-memsave-mem 以及 migrate-mem 的 skill 来和上面的功能进行呼应

具体配置

安装配置 claude-mem

1
npx claude-mem install --ide opencode

运行这个官网上的命令就能直接安装了,不过需要注意一点。这个是在 ~/.config/opencode/plugins 下面安装了一个 claude-mem.js 的插件脚本。同时对应的服务是运行在 ~/.claude/plugins/cache/thedotmack/claude-mem 的一个目录下。同时这个 claude-mem.js 只是提供了一个 search 工具。假如想要更多工具,可以在 opencode.jsonc 中配置 mcp 服务器。

1
2
3
4
5
6
7
8
9
{
"mcp": {
"claude-mem": {
"type": "local",
"command": ["~/.bun/bin/bun", "~/.claude/plugins/marketplaces/thedotmack/plugin/scripts/mcp-server.cjs"],
"enabled": true
},
}
}

然后在 ~/.claude-mem/settings.json 中的配置就如下所示,大家基本都是自定义API,比如使用 NewAPI,所以初始化配置的时候选择 OpenRouter,API那里随便输入字符串就行了,可以自己去 json 文件中进行细节配置,这里的 openrouter 背后的格式就是 openai-compatible 了

1
2
3
4
5
6
7
8
{
"CLAUDE_MEM_RUNTIME": "worker",
"CLAUDE_MEM_PROVIDER": "openrouter",
"CLAUDE_MEM_OPENROUTER_BASE_URL": "BASE URL",
"CLAUDE_MEM_OPENROUTER_MODEL": "model name",
"CLAUDE_MEM_CONTEXT_OBSERVATIONS": "20",
"CLAUDE_MEM_OPENROUTER_API_KEY": "API Key"
}

自行替换这里的路径即可,目前的 claude-mem 的插件脚本并没有注册全部 mcp 工具,要使用更多的 mcp 工具就需要把本地运行这个 mcp-server.cjs 的脚本

安装配置 magic-context

1
curl -fsSL https://raw.githubusercontent.com/cortexkit/magic-context/master/scripts/install.sh | bash

运行这个官网提供的命令即可。

对应的配置文件为 ~/.config/cortexkit/magic-context.jsonc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"$schema": "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
"historian": {
"opencode": {
"model": "提供商/模型"
}
},
"execute_threshold_percentage": 65, // 模型 input 的百分比,达到 65% 开始进行记忆存储,后续还会有裁剪
"embedding": {
"provider": "openai-compatible",
"model": "text-embedding-3-large",
"endpoint": "BASE URL",
"api_key": "API KEY"
},
"dreamer": {
"opencode": {
"model": "提供商/模型"
}
},
"sidekick": {
"disable": true
}
}

配置 historian 和 dreamer 两个 Agent 的模型,这里使用 opencode.jsonc 中配置的提供商和模型即可,然后再单独配置一下 embedding

注意:一定要记得禁用 opencode 内置的 compact 功能,不然和 magic-context 冲突,opencode.jsonc 的配置如下

1
2
3
4
5
6
7
{
"compaction": { "auto": false, "prune": false },
"plugin": [
"@cortexkit/opencode-magic-context@latest",
]

}

Strict Doc 配置

这个配置没啥好说的,主要是配置个 python 环境,让 Agent 去配置就行了。

定期让 Agent 更新一个项目文档,要人能够看懂,claude-memmagic-context 本质是面向 Agent,面向会话上下文的,而 Strict Doc 是面向开发者用户的

Skill & AGENTS.md 配置

下面是 load-mem 的 SKILL.md

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
---
name: load-mem
description: load all memory layers (injected memory, StrictDoc project_memory, claude-mem history) plus core files to understand the project
---

Build an understanding of this project from all available memory layers, then verify against core files and directory structure.

**Memory layers (in priority order):**

1. **Injected project memory** — the `<project-memory>` block in your system prompt is already loaded. Do NOT re-fetch it. It is the authoritative source for constraints, config values, and conventions.
2. **File memory (StrictDoc)** — `docs/` is one StrictDoc project with two trees: `project_memory/` (memory: `decisions.sdoc` for 口径+初衷, `journal.sdoc` for progress) and `handbook/` (durable documents: specs, research, evaluations). Read the `.sdoc` files directly:
- Nodes carry `UID` (stable anchor), `STATUS`, `STATEMENT` (the decision itself), `RATIONALE` (why it was made).
- **STATUS discipline: only `Active` nodes are current canon.** `Deprecated`/`Superseded`/`Proposed` nodes are history — never quote them as current practice. When a node is Superseded, follow the relation to its successor.
- To query precisely instead of reading everything: `strictdoc export --formats=json .` in `docs/`, then e.g. `jq '.DOCUMENTS[].NODES[] | select(.STATUS=="Active")' output/json/index.json`.
3. **Action history (claude-mem)** — a passive log of past tool activity with semantic search. If the files look stale or you need "what was actually done recently", use the `claude_mem_search` tool (fallback: `curl http://127.0.0.1:37700/...` worker API). Treat results as leads, not gospel — verify against files/git before acting on them.

**Then ground it in code:**

- Glob the directory structure and read core files to confirm the memory matches reality.
- In projects not yet migrated, legacy markdown may still exist in other subdirectories under `docs/` (e.g. old `superpowers/`, `research/`). Skim for context but treat as historical until migrated into `docs/handbook/`.

You can use ripgrep and naive grep, and load relevant skills as needed.

下面是 save-mem 的 SKILL.md

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
---
name: save-mem
description: save memory according to current state and progress — durable facts to ctx_memory, narrative to StrictDoc project_memory
---

Record the current state so the next session can resume quickly. Extract the most core and important content. Be concise and to the point.

**Route by content type — do not dump everything into files:**

1. **Durable operational facts** (constraints, config values, naming conventions, architecture facts, hard-won workarounds) → write to `ctx_memory`. These are auto-injected into every future session.
2. **Project narrative** (progress, decisions with rationale, next steps) → the `docs/project_memory/` tree (see below).
3. **Durable documents** (specs, research reports, evaluations, design docs) → the `docs/handbook/<topic>/` tree (see below).
4. **Follow-ups for later**`ctx_note`.
5. **Action details** (which commands ran, which files were touched) → do NOT record. claude-mem captures tool activity automatically.

**Writing to `docs/project_memory/` (memory tree):**

- **Decisions** go to `decisions.sdoc` as `[DECISION]` nodes: `UID` (DEC-XXX-NNN), `STATUS` (Proposed/Active/Deprecated/Superseded), `TITLE`, `STATEMENT` (the canon), `RATIONALE` (the original motivation — always fill this; losing it is a known pain point).
- **Progress entries** go to `journal.sdoc` as `[TEXT]` nodes with a date UID (e.g. `JOURNAL-2026-08-26`), referencing decision UIDs where relevant.
- **Never delete or rewrite a node.** To retire one: set `STATUS: Deprecated` or `Superseded` and add a `RELATIONS: - TYPE: Parent / VALUE: <successor UID> / ROLE: Supersedes` link from the successor node.
- **Validate after every write**: run `strictdoc export .` in `docs/` (covers both trees). A parse error must be fixed immediately — never leave the tree broken. Environment: prefer plain `strictdoc` from the currently activated Python env (the agent shell usually inherits the user's conda/uv/venv env). If it's not on PATH, detect the project's env (e.g. `.venv/bin/strictdoc`, `uv run strictdoc`, or a named conda env) — do not assume `.venv`.
- SDoc strict rules: one empty line between nodes, no content outside grammar elements, no empty optional fields (omit them). Sections use ONLY the double-bracket form `[[SECTION]]`/`[[/SECTION]]` — the single-bracket `[SECTION]` was removed in strictdoc 0.28.3 (processor error). If export fails with "[SECTION] elements are no longer supported", some file uses the single-bracket form — fix with: `find . -name '*.sdoc' -exec sed -i -e 's/^\[SECTION\]/[[SECTION]]/g' -e 's/^\[\/SECTION\]/[[\/SECTION]]/g' {} +`

**Writing to `docs/handbook/` (document tree):**

- One `.sdoc` per document under a topic subdir (e.g. `handbook/research/`, `handbook/specs/`).
- `[DOCUMENT]` header has no UID field — use `TITLE:` + `DATE:`; add `OPTIONS:` with `MARKUP: Markdown` (the default RST chokes on ``` fences and `backticks`).
- Map `##` headings to `[[SECTION]]` + `[TEXT]` nodes; **every section must be closed with `[[/SECTION]]`**.
- Keep the content verbatim; structure is the only thing you add.

Chinese is preferable for node content, but English is acceptable; you may mix. Clarity matters most.

下面是 migrate-mem 的 SKILL.md

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
37
---
name: migrate-mem
description: migrate an existing project's scattered/flat legacy memory files and documents into the three-layer memory system (ctx_memory + StrictDoc project_memory/handbook). Use when adopting the memory stack in a project that already has accumulated messy memory notes or docs.
---

Migrate legacy memory files into the three-layer system WITHOUT losing information or misjudging what is still current. Work in phases; the classification plan must be reviewed by the human before any writing.

**Prerequisites (verify first, stop if missing):** strictdoc env installed (pin the version, e.g. `strictdoc==0.28.1`, and keep it identical across machines — GitHub releases run ahead of PyPI and 0.28.3 removes single-bracket `[SECTION]`), `docs/` StrictDoc skeleton exists in the v2 layout (config at `docs/strictdoc_config.py` + `project_memory/` + `handbook/` trees), project `AGENTS.md` trigger block in place. If the skeleton is absent or a different layout, stop and ask the human — do not improvise a restructure.

## Phase 0 — Safety

- Copy every legacy memory file to `docs/_memory_archive/` (OUTSIDE the two sdoc trees, preserving paths). Originals are only moved, never deleted, and only after the final report is accepted.

## Phase 1 — Inventory

- Find all memory-bearing files: old `docs/project_memory/*.md`, scattered NOTES/TODO files, spec/plan/research/evaluation docs under `docs/` subdirectories, root-level notes.
- Read them fully (chunk large files; keep a ledger file so compaction loses nothing). Extract discrete items, each tagged: operational fact / decision / progress / durable document / action trivia / obsolete — with its source file path.

## Phase 2 — Classification plan (HUMAN CHECKPOINT)

- Route each item per the standard rules: durable operational fact → `ctx_memory`; decision → `[DECISION]` node; progress/status → `journal.sdoc`; durable document (spec/research/evaluation/design doc) → `docs/handbook/<topic>/` via md→sdoc wrapping (see Phase 3); pure action trivia → drop (claude-mem covers it).
- Contradictions: pick the current canon, mark losers as `Superseded` with a relation to the winner. If you cannot tell which is current, mark the item `STATUS: Proposed` and flag it — do NOT guess.
- **Never fabricate a RATIONALE.** Only write one when the original motivation is discernible from the source text; otherwise omit the field. An invented rationale is worse than a missing one.
- Present the plan as a table (item → destination → STATUS → reason) and STOP for human approval. On first migration of a project, always stop; on later runs, stop only if conflicts or Proposed items exist.

## Phase 3 — Execute (after approval)

- UIDs: scan existing nodes, continue the sequence; topic prefixes (DEC-MEM-*, DEC-AUTH-*, ...).
- Write `decisions.sdoc` / `journal.sdoc` nodes. STATEMENT keeps the original wording of the canon (light clarity edits only).
- **Document wrapping (md → handbook sdoc)**: one md file → one `.sdoc` under `docs/handbook/<topic>/`. `[DOCUMENT]` header: `TITLE:` + `DATE:` (no UID field exists) + `OPTIONS:` with `MARKUP: Markdown`. Map `##` headings to `[[SECTION]]` + `[TEXT]` nodes (double brackets ONLY — single-bracket `[SECTION]` is removed in 0.28.3+); close every section with `[[/SECTION]]`. Content stays verbatim — you add structure, not prose.
- Write `ctx_memory` entries for operational facts — list existing memories first to avoid duplicates.
- Validate after EVERY file edit: `strictdoc export .` in `docs/`. Fix parse errors immediately. Prefer plain `strictdoc` from the activated Python env (conda/uv/venv — the agent shell usually inherits it); if not on PATH, detect the project's env instead of assuming `.venv`.

## Phase 4 — Report & archive

- Report: counts by destination, conflicts resolved (and which side won), `Proposed` items awaiting human confirmation, dropped trivia.
- Move originals into `docs/_memory_archive/`. Confirm `strictdoc export .` still passes.

还有一个就是 AGENTS.md 的 tail 内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- memory-system:start -->
## Project Memory System

This project uses a three-layer memory system (Magic Context + StrictDoc + claude-mem).

- **At session start**: run the `load-mem` skill before doing substantial work.
- **At milestones and before ending work**: run the `save-mem` skill.

### Rules that always apply (even if the skills are not loaded)

1. `docs/` is a single StrictDoc project with two trees: `project_memory/` (memory: decisions, journal) and `handbook/` (durable documents). Only nodes with `STATUS: Active` are current canon; `Deprecated`/`Superseded`/`Proposed` nodes are history — never quote them as current practice.
2. Never delete or rewrite memory nodes. Retire via `STATUS` change plus a `Supersedes` relation to the successor node.
3. After editing any `.sdoc` file, validate immediately: run `strictdoc export .` inside `docs/`. Prefer the `strictdoc` on PATH (the activated conda/uv/venv env is inherited by the agent shell); if absent, detect the project env (e.g. `.venv/bin/strictdoc`, `uv run strictdoc`) — do not assume a specific env manager. Never leave the tree broken.
4. On conflict between memory sources, `ctx_memory` (the injected `<project-memory>` block) wins.

(Procedures for reading/writing memory live in the `load-mem`/`save-mem` skills — keep this file short.)
<!-- memory-system:end -->

这几个 SKILL.md 是我自己的一些 artifacts,每个人都有自己的爱好,这个是我个人迭代出来的,专门做了一个 migrate-mem 来将我之前的一些老项目迁移成我想要的这种记忆文档系统的框架。这里的 AGENTS.md 力的这段用 <!--> 包裹起来的,就是放到 AGENTS.md 的结尾处的,用于诱导 Agent 使用这些规范而已。

总结

我主要是设计了一个 docs/project_memory 用来存储项目相关的记忆,让人能够知道这个项目发生了什么,做过什么。然后又设计了一个 docs/handbook 专门来搭建项目文档。然后都通过 Strict Doc 来方便进行可视化,既方便人类阅读,也方便 Agent 来探索。

然后 claude-mem 会通过 hook 的系统来一步步在后台进行记忆的 dump,这里会记住许许多多的细节信息,但是这个系统并不知道任务主线,项目细节是怎样的,只是有什么就记下来,这套记忆系统做的很好。

magic-context 也有记忆功能,不过他这个记忆功能肯定做的没有 claude-mem 好,但是他还有一个好处就是能够在上下文超限的时候,由模型来进行合适的上下文裁剪,并且在上下文累积的时候,也会进行记忆的 dump,不过不是 claude-mem 那样机械式的进行存储,而是由Agent通过工具调用自主决策记忆什么内容。所以他维护近期记忆,和长期规范的能力比较好,也就是说你给他一大段的规范文本,着重强调之后,即使经过裁剪,它能够延续你的这个任务主线和目标进行开发,因为 magic-context 本质上是挑选哪些块留下,哪些块压缩,但同时能给出一个 context 的索引,因为之前存储过,以及用户给的输入基本上也都能留下来。不像 opencode 内置的 compact,真的就是全盘替换内容,替换成他压缩的那么一套 Details, Next Move 那一套文本,那套基本上全乱套了,各种细节全没了。

然后通过 load-memsave-mem 的 SKILL 搭配 AGENTS.md 尾部的这一个提醒块,进行一个逻辑口径的闭环,让 Agent 知道咱们有这么多工具可以用。用来让 Agent 更积极的进行记忆的保存和取出。

目前的想法就是这样,现在这样 gpt-5.6-sol 的 372K 上下文是完全够用的,并且全程用下来就是不会失忆的。并且能够在一个会话中,进行一次次的任务发布,细致修理,完成,再到下一阶段任务的发布。综合用起来,不用再频繁的进行 HANDOFF 然后去新的会话中进行 HANDOFF 的转接了。

所以推荐在进行所有的任务操作前都进行一次细致的 grilling 操作,做完之后,Agent 基本就能死死记住这些内容,后续的上下文都由 magic-context 来控制,用不到 opencode 内置 compact 了。哪怕是非常长的同质化的内容操作,比如对一个批量的目录下面的代码做成相同语义的更改,这样也不会因为爆上下触发 compact 而导致最初的任务语义发生更改。这一点是我最喜欢 magic-context 的一点。

Agent 能从设计的 docs/ 目录中找回记忆,找回规范,也能从 magic-context 提供的工具中找回记忆,最后还能从 claude-mem 中找回之前精准的都做过什么。再通过这一套插件式闭环的 SKILL 文本引导系统,感觉这下做的挺不错了,真的不虚 codex 和 claude code 了~~~

所以大家记得在对话中有意无意的,超绝不经意的加一句的,记得在明确所有规范后保存一下记忆,或者 记得在完成所有的任务内容后,也更新一下记忆你感觉你踩了哪些坑,也可以记录一下。基本能做到 Agent 不会在同一个坑里面踩两次了。比如某个 LD_LIBRARY_PATH 变量没设置导致哪个 libxx.so 找不到的报错,减少上下文噪声,模型智商也就能感觉到噌的一下变高了~

嗯,大概就是这么多了,干项目在Agent转呀转呀的时候去并行的陪人熬夜打游戏,起来之后牙没刷,饭还没吃想着来发个帖子,饿了,觅食~~

Multisim Edu PLD 的使用

之所以想要写这篇文档是因为有许多同学(包括我自己在内)都被误导,认为 Vivado 只能装在 C 盘内才可被 Multisim 识别。这在我之前的有关于 Multisim 的安装的文档中讲到过。其实装在 C 盘说可以让 Multisim 自动识别到 Vivado,我们其实可以手动指定 Vivado 的位置。这篇文档将会从 Multisim 进行 basys3 FPGA 开发板实验讲起。

省流:Vivado 是可以装在 C 盘以外的盘的。不需要专门为 C 盘扩容去安装几十个G的Vivado

假如你不会 Multisim PLD 的使用建议从头阅读,假如你熟悉使用,就是想知道 Vivado 装在 C 盘以外的盘如何处理,直接跳至末尾看 Vivado 不在 C 盘即可 即可。

Multisim PLD 的操作流程

操作环境

  • 操作系统:Windows 10
  • 容量:40 个 G 起步(Vivado 2018.3)
  • 软件:Multisim 14.2 Edu,Vivado 2018.3

同样不推荐 Mac 用户。Mac 用户另请高明,或者老老实实使用实验室电脑。

建立项目

新建一个 Multisim 项目,如图选择新建 PLD 支电路

一般都建议选支电路不要选层次块。以及后续开发在 PLD 模块中自己搭建模块时也用支电路而不用层次块。具体原因为支电路仅仅在这个工程内有效。而如果想在其他工程中使用其实可以通过简单的复制粘贴过去,此时两个工程间的两个模块互不映像。而如果选用层次块,层次块自己创建一个文件与之对应,修改这个层次块会修改这个文件。此时如果两个工程用同一个层次块,这边修改,另外一边也会跟着修改。除非你的模块已经做的非常好了,在每个工程中都能用,且保证自己不会去修改它。就像 C 语言中的库函数一样,你不会去改库函数。但考虑到大家的时间有限,很难自己能搭出一个万能的模块,还是建议大家用支电路,这个也允许在不同工程之间复制粘贴。

选择新建支电路.png

选择配置 —— basys3

选择 basys 3 选项.png

数字电路实验使用的时 Basys3 开发板,固定选择如图配置就行。后续还可以自定义 PLD 模块名称,选择 PLD 模块的 IO 口。在此不作展示。仅仅说明原理。

原理:Basys3 开发板上有许多引脚这些都是固定的,全都有自己的名字编号的。Multisim 中也存有 Basys3 的资料库,所以其直接提供好了那么多引脚,你只需要选择你需要的引脚即可。如 JB0,JB1,SW0,SW1,LED0,LED1等等。这些编号全都有其对应的外部设备对应(称为“外设”)。

如下所示已经搭建好了一个 PLD 模块

PLD模块.png

搭建门电路

上述那个 PLD 模块其实就是 Basys3 开发板,我们需要在 Basys3 开发板里面搭建自己的逻辑电路,所以我们需要点进去这个模块,点进这个模块可以双击这个 PLD 模块然后点打开子电路,也可以将鼠标悬停在 PLD 模块上会在左上角出现一个小标志,点击这个小标志也能进去。当然也可以看左边的资源管理器视图,当前是 Design1,点击下面的那个 PLD 就可以进子电路了。

放置门电路.png

如上是已经在子电路里面并且搭建了一个简单的与门的逻辑电路。从拨码开关 SW0 和 SW1 读入电平信号,相与后输出至 LED0 对应的 LED 灯。

烧录成 bit 流

前面都很简单相当于是废话,这里才是重中之重,误导了一批又一批人,包括我在内,包括实验中心老师在内。

将这个逻辑电路烧录成硬件可读取的 bit 流,才可被 Basys3 开发板运行。这里的操作是要去后台调用 Vivado。

然后悲剧的是曾经一度以为 Vivado 只能在 C 盘才可被 Multisim 识别。其实这句话应该被改为 Vivado 只有在 C 盘才可别 Multisim 自动识别。如下所示。操作如下。

点击左上角的那个 导出至PLD 的小按钮。(鼠标悬停在这个按钮上会出现这个字样)点击之后出现如下界面

选择生成选项.png

  • 第一个选项的意思是生成 bit 流,同时将这个 bit 流烧录至开发板中(此时需要你的电脑已经连接了开发板,如果没连接则无法操作成功)
  • 第二个选项的意思是只生成 bit 流,省去了烧录到开发板的过程,这时你的电脑不需要连接开发板也可生成 bit 流。
  • 第三个选项不重要,至少我都没用过。。。。

在该演示中因为没有开发板,所以这里选择第二个。接下来进入到了最重要的下一步。

以下是 Vivado 装在 C 盘的情况。

自动识别.png

  • 可以看见这里识别出来了 Vivado,但这里有个(不被支持)字样。注意,在我看来,这应该是个bug,其实这个不被支持并不影响使用,忽视即可。
  • 下面的那个编程文件就是输出的 bit 流文件,可以自定义名称和地址。
  • 再下面的这个高级设置要注意。这里有个 Xilinx user constraint files(*.xdc) 的选项。可以看出他需要一个 xdc 后缀的文件。这个文件一般是在 Multisim 的安装目录下。进入你的目录,我这里的默认目录是 C:\Program Files (x86)\National Instruments\Circuit Design Suite 14.2\pldconfig。就是在这个 pldconfig 目录下,有这些 xdc 文件。这里是使用 Basys3 开发板,故选择 DigilentBasys3.xdc 这个文件。

注意,这个文件一般是默认配置好的,但也会,并且是经常会出现弄错的情况,或者这一栏是空的,这时候就需要去自己去手动选择,点击右边,点击那三个小点,可以打开文件资源管理器,选中对应 xdc 文件即可。

下面这个是点击完成后出现的正在处理计算的界面。这里是 2 步,如果你之前选择了第一个选项则是 4 步。

正在烧录.png

这里成功生成,可以看到左下角显示 0 错误 0 警告。代表已经成功生成了 bit 流

0错误0警告.png

此时便可在对应的路径下找到这个 bit 流文件

这样一套下来点击完成就可以去烧录了。再看接下来的情况,是 Vivado 不在 C 盘的情况。

Vivado 不在 C 盘

没有vivado.png

Vivado 不在 C 盘时这个界面如下,没有识别到 Vivado。此时可以手动添加。

点击右边这个 Browse,选择 Vivado 所在的目录。这里以 Vivado2018.3 举例(推荐搭建安装2018.3的版本,只有40个G,且也能完成任务)

选中 Vivado 对应的版本的那个文件夹就行。如下所示。选中这个 2018.3 的文件夹即可。点击确定即可成功找到

选择vivado.png

成功添加后如下所示,显然与之前自动识别出来的效果一样,虽然还有一个不被支持字样。但可以看见后面有个 User specified,代表是我们指定的。不是 Multisim 自己找到的。两者没有任何差别。

注意(很重要):这时候眼尖的小伙伴就发现了,这里 .xdc 文件怎么在 D 盘里面啊。这是因为这个素材来自另外一台电脑,这里的截图素材并不完全来自同一台机子。这里的情况是因为这个 xdc 文件路径里面带有中文,也就是说,Multisim 并没有装在默认位置,而是装在了自定义的文件夹里,而且这个文件夹带有中文(太悲催了,buff 叠满了)。这时候就无法读取,需要另外新开一个无中文的路径,把 xdc 文件拷贝过去。

已经选择好配置.png

总结

以上就是这么多。总共分为以下几点

  1. Multisim PLD 的使用教程(比较简单)
  2. 可以只生成 bit 流而不写入开发板
  3. Vivado 也可以不装在 C 盘(重要)
  4. xdc 文件不能有中文路径(重要)

祝大家数电实验愉快!

附上我的邮箱:[email protected]

介绍

rime 是一个相对来说比较好用的输入法(就我自己看来,虽然说也有其他大佬觉得这个已经是很久以前的了,并不值得现在进行提倡)

就我个人而言我都是用他来实现双拼和全拼的使用。一般来说 Windows 上的双拼可以直接使用微软输入法进行实现,直接改注册表即可,方便又简单

而 rime 的实现则就相对复杂起来了,需要一些配置文件。

文件

default.yaml

这个文件是 rime 的默认配置,里面记录着其自带的所有的输入法,这就是为什么刚用 rime 时会有那么多方案选项。这个文件一般位于 build 文件夹中,Windows 和 Ubuntu 下都是如此。

但这里有一点很重要,就是在 Ubuntu(22.04LTS) 下,使用的是 fcitx5-rime 的时候,这个文件在 /usr/share/rime-data/~/.local/share/fcitx5/rime/build 中各有一份。

default.custom.yaml

这个文件也是配置文件,与上面不同的是,一般认定(其实不用遵守也行)不篡改默认配置文件,如果想要自定义即可在这个文件中进行修改,这个文件里面的配置具有更高的优先级,可以覆盖上面的相同的配置。这个文件的位置有讲究,不能随便在一个文件夹中创建,否则将部署失败。

default.custom 里必须要写 patch 表示是上面文件的补丁才行,不然无效。

具体部署规则

这里以 fcitx5-rime 为例(事实上 ),具体的部署规则是这样的,在/usr/share/rime-data/中有着其原始的数据,即使用apt下载时就是直接解压到了这个位置,当然不同系统apt下载解压的位置可能不一样,但我们就是认这个apt的源文件解压位置。这里还有个build文件夹,在这个文件夹中有着几乎所有的输入法的.bin .txt .yaml 配置文件和执行程序以及词典。当然像双拼这种应该还需要另外进行下载,使用 sudo apt install rime-data-doublepin 即可,同样是会解压在这个位置。

只有这里建立的 default.custom.yaml 才会有效,而在~/.local/share/fcitx5/rime/build这条路径下的,则没有这个效果。并且在.local 这个路径下的default更改也没用,因为每次部署时这个default本身时usr目录下的那个 default 和 default.custom 的叠加组合。

另外我们还需要将usr路径下的相关文件复制过去,例如我要小鹤双拼,我就需要将这里的build文件夹下的(其中会有所有的输入法的相关文件)double_pinyin_fly.schema.yaml 和他的bin文件以及txt文件都复制到.local路径里的那个build目录下。

所以我在 default.custom.yaml 里记录的是

1
2
3
4
5
6
patch:
schema_list:
- schema: double_pinyin_flypy
- schema: luna_pinyin
menu:
page_size: 7

然后我将下面这些文件从 /usr/share/rime-data/ 复制到 ~/.local/share/fcitx5/rime/build 目录下,然后重新部署大功告成。

1
2
3
double_pinyin_flypy.prism.bin
double_pinyin_flypy.prism.txt
double_pinyin_flypy.schema.yaml

Qt Creator 工程

初始化

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
namespace Ui { class MainWindow; }
class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();

void TrtInfer(const std::string& model_dir, const std::string& video_file);

QGraphicsScene scene;
// QPixmap pixmap;
// QImage image;

private slots:
void on_ok_btn_clicked();

void on_quit_btn_clicked();

void on_show_btn_clicked();

public slots:
void show_result();

private:
Ui::MainWindow *ui;
};

初始化大致如上所示。其中 Q_OBJECT 乃是宏定义,记录了一些默认的元数据(成员变量,成员函数)

编译运行

先前使用的是 qmake,qmake 我懒得看到底怎么弄了,干脆直接用 QtCreator 来实现就行了。

2023 年了,使用 cmake 进行编译。QtCreator 中的默认的 cmake generator 命令如下所示:

1
2
3
4
5
6
cmake -DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable} \
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX} \
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C} \
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx} \
-G"CodeBlocks - Ninja" \
-S {source_director} -B {build_directory}

部署(build)运行命令很简单

1
cmake --build {build_dirctory} --target all

上面的是使用 QtCreator 图形化界面来进行完成的。实际上只是点击部署,运行按钮会出现这些东西。

我还尝试了一下仅使用命令行来运行 Qt 工程,也可以成功,命令如下

1
2
3
4
5
6
7
8
9
$ mkdir build && cd build

# 创建 build tree
$ cmake .. -D{必要的自定义宏}

# 生成 target
$ cmake --build . --target all
或者尝试使用 make
$ make

其中上面的宏,我并没有像 QtCreator 中一样有那么多,其实完全都可以不用宏(假如这个 Qt 程序不联合其他的工程)便可以跑起来。

Qt 语法

字符串

Qt 中字符串有 QString 和 QTextStream 类型。当然,也有 QChar 的类型。

其中就有涉及到给字符串写入的操作。在 Qt 的文档中,原本有 asprintf() 可以调用,相当于 sprintf() ,但是 Qt 特别说明了不建议采用这个

Warning: We do not recommend using QString::asprintf() in new Qt code. Instead, consider using QTextStream or arg(), both of which support Unicode strings seamlessly and are type-safe. Here is an example that uses QTextStream:

如上所述,可以使用 arg()QTextStream 来进行赋值

1
2
3
4
5
6
7
8
9
10
11
12
QString tempport;

//QTextStream 赋值
QTextStream aa(&tempport) ;
aa.setCodec("UTF-8");
aa << tr("using QTextStream\n服务器端口: ") << port;

//arg()赋值
tempport = QString("服务器地址: %1\n服务器端口: %2\n").arg(IP).arg(port);

//直接赋值
tempport = "服务器地址: "+ IP + "\n" + "服务器端口: " + QString::number(port) + "\n";

QString 和 char* 转换网上有许多种说法。和一旦出现中文 char* 转换为 QString 许多方法都会出现乱码的情况,我在 Qt 官方论坛中看到一个方法,不用导入 GBK 编码的方法。

1
2
std::string str = Msg.toStdString();	//Msg QString型变量
const char* p = str.c_str(); //char型中文大多数占用3个字节,少数4个字节

展示图像

展示图像代码如下所示,这里考虑的是从 cv::Mat frame 来转换到 Qt 显示图像的。这里有个重要的细节是 scene 必须不能是一个局部变量,否则图像将无法显示,应该用全局变量,或者成员变量。这是我自己测试出来的,没看 Qt 文档到底是怎么回事。

1
2
3
4
5
void MainWindow::show_image(){
scene.addPixmap(QPixmap::fromImage(QImage(frame.data, frame.cols, frame.rows, frame.step,QImage::Format_RGB888)));
ui->graphicsView->setScene(&scene);
ui->text_plain->setText("Just show an image");
}

类成员变量

有类成员变量的话建议使用指针,这样可以自己在构造函数或者在其他函数中来创建这个成员变量,从而清晰的调用这个类成员变量本身的构造函数。例如 QThread ,仅仅举个例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyThread; // 前向声明
class MainWindow : public QMainWindow {
MainWindow(){}
~MainWindow(){}
MyThread * t;

void MyCreateThread(){ t = new MyThread(); t->start(); }
}

class MyThread : public QThread {
MyThread() {
...
}
~Mythread(){}
}

调试

某些情况下 Qt 不允许两个调试器同时在调试,所以我在同时调试客户端和服务端时出现异常报错

Unexpected run control state RunControlState::Running when worker DebuggerRunTool started

在 Qt 论坛找到的说法是

It could be that you had indeed two debugger sessions running. I just noticed that the views including the ‘active’ frame marker in the stack view are not changed properly right now.

改为一个运行,一个调试之后,这个报错消失。

Qt 工具

uic/pyuic5/pyside6-uic

可以用来将 ui 文件进行转换,转换成 cpp 文件,Python 文件。使用 Qt Designer 设计 ui 后,使用这个工具转换成代码,直接调用即可。

1
pyuic5 -o form_ui.py form.ui

rcc/pyrcc5/pyside6-rcc

与上面的同理,用来将 qrc 资源文件转换成对应的文件。

1
pyside6-rcc background.qrc

程序依赖问题

Qt5LinguistTools

在 Ubuntu20.04 上有时库若安装不完全,会报这个库相关的 cmake 文件不存在的错误。只需要安装相应的包就行。在 Ubuntu 官网查询这个关键字能查到需要安装如下包:

1
sudo apt install qttools5-dev

安装完之后能够看到相应的目录 /usr/lib/x86_64-linux-gnu/cmake/Qt5LinguistTools

Qt6 安装问题

Qt6 没有发布安装文件,只给了源代码,可以进行编译然后安装。在 Qt 官网查询得到 Ubuntu 需要 gcc11 套装才能进行编译。与 Ubuntu20.04 无缘,遂没安装。

但奇怪的是由 python 管理的 PySide6 却可以进行使用。

fcitx5 输入法问题

使用 PySide6 和 PyQt5 时在输入框中不能使用搜狗输入法。搜狗输入法本身基于 fcitx5。需要下载安装相应的 qt-fcitx5 的包(一系列,不具体叫这个名字)

在网上得知可以在 Github 上找到相应的 fcitx5-qt 的仓库,克隆下来进行编译即可得到相应的 libfcitxplatforminputcontextplugin.so 的动态链接库,将这个动态链接库复制到 Python 环境相应的位置即可。

程序打包移植

添加所有动态链接库

使用ldd可以将所有的隐式动态链接库罗列出来,然后再使用 awk 可以将动态链接库全部单独列出来

1
2
3
4
# 在可执行文件所在目录下操作
ldd Program > dependancy.txt
dll=$(cat dependancy.txt | awk "print $")
cp $dll ./lib

添加动态链接库路径

1
export LD_LIBRARY_PATH=$LD_LIABRARY_PATH:${PWD}/lib

添加动态库路径会出现段错误,因为会出现库的冲突,主要在于 LD_LIBRARY_PATH 的库与默认库冲突,即打包时也打包了系统库,运行时,两个库出现冲突(可能是系统不同导致,可能就是不允许出现两次)。

libc6 兼容(操作系统兼容)

21.10 支持到libc6(2.34)版本,而20.04只支持到2.31版本。

使用DEBUG调试

1
export QT_DEBUG_PLUGINS=1

对于转移后出现的问题的程序,这样可以详细的罗列程序执行到哪一步出错。一般都是 XCB 出错。

STM32F407

我在网上看到很多奇奇怪怪的东西。其中就有一个STM32F4discovery,这个我不知道是啥,但总是会看到。包括使用CLion时配OpenOCD时都会跳出它的config文件。但最后我选的还是STM32F4xx的config。在此还得感谢@Keiler提供的友情帮助,帮我暂时配好了CLion的开发环境。有关于CLion开发环境的配置我在另一篇文档中有讲述。

开发环境:

板子:正点原子探索者开发板

MCU:STM32F407ZGT6

串口:RS232

屏幕:TFTLCD(已损坏)

软件:CLion + STM32CubeMX 以及 Keil

教程:正点原子官方配套例程

下载器:ST-Link

串口配置

配置串口让我很是头疼。基本照着网上的来一遍都可以。但是其中还有一些细节——一个是将 printf() 函数重定向到串口,一个是要配置 HSE_VALUE 的值,因为它直接影响到串口波特率的配置。

  1. printf() 重定向:直接参考这篇文档,这篇文档讲的非常详细,只要在 usart.c 文件末尾加上以下代码,另外还需在 usart.h 头文件中 #include <stdio.h> 即可。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    /* USER CODE BEGIN 1 */
    #ifdef __GNUC__
    /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
    set to 'Yes') calls __io_putchar() */
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
    #else
    #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
    #endif /* __GNUC__ */
    /**
    * @brief Retargets the C library printf function to the USART.
    * @param None
    * @retval None
    */
    PUTCHAR_PROTOTYPE
    {
    /* Place your implementation of fputc here */
    /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);

    return ch;
    }
    /* USER CODE END 1 */
  2. 配置HSE_VALUE:参考这篇博客,这篇博客讲到 HSE_VALUE 如何影响到串口波特率的配置问题。我遇到的问题是使用 STM32CubeMX 直接自动生成 168MHz 的时钟,这里了他默认的外部时钟为25MHz,即 HSE_VALUE = 25000000。而我对比了正点原子的官方串口通信例程中的值,例程中的值则为8MHz。所以我的串口一直乱码,而例程则不会乱码,将 HSE_VALUE 改为8MHz时,串口通信正常。

至此,串口配置完毕。此后我便可以通过串口进行通信了!!!耶比

定时器中断配置

定时器中断,这里我使用的是定时器TIM3,进入

CLion-STM32-OpenOCD配置

这个配置,恕我直言,真的过于阴间。这个 的配置前前后后我不知道配了多久,对着网上的教程进行配置。这里我将其记录下来,然后说出我的一些经验怪谈。

配置这个东西,首先你随便上网一查都能看到需要下载 CLion(收费,但是学生免费),STM32CubeMX,以及OpenOCD。然后你还需要 gcc-arm-mingw。

OpenOCD

直接搜索下载安装即可,然后假如环境变量即可。

STM32CubeMX

也是直接下载安装即可,至于要不要导入软件包倒也无所谓,因为在你实现工程的时候,自然而然会给你下载所需要的包。提前装好也不失为一种好的省事的选择。至于如何提前导入包直接百度即可。

arm-none-eabi-gcc(g++ …)

这个下载也是直接搜索下载安装即可,然后加入环境变量

配置环节

首先直接按照网上的各种教程将 STM32CubeMX 和 OpenOCD 都加入到 CLion 的配置里面。然后点击 test 看看是否可以识别成功。

然后可以在 CLion 的设置里面新建一个工具链其中使用之前所提到的 arm-none-eabi-gcc 和 arm-none-eabi-gdb,不过对于这里,我还是存在疑问,是否应该这样做?还是说有其他的做法,还是这种做法没什么用。因为我看到网上也是各种参差不齐的说法,也有说不用这个 gdb 直接用 bundled gdb 就行的,看得我也晕了。。。

但就我自己的体验而言,好像这都没什么大用。我甚至都用的是 ninja。程序也能跑起来,就没管了。所以重点还是在后面怎么无脑的机械式的生成能跑,只管自己编写逻辑代码的工程。

创建一个能跑的工程

直接 CLion 中新建一个工程,起一个名字,便是新建了一个 文件夹。创建的过程中肯定是选择 STM32 的那个选项啦。

然后 CLion 会自动生成一个同样工程名的 .ioc 文件,这个文件是用 STM32CubeMX 来打开编辑的。你直接选中然后用 STM32CubeMX 打开就行了,然后进行属于 STM32CubeMX 的操作环节就可以了。这里最后会有一个文件夹和名字的设置,加入这里自己又设置了其他名字,最后这个 .ioc 文件的名称会被这个覆盖,变成这个名字,不过也没什么大碍。

这里一定要选择 STM32CubeIDE 的模式,不能选择 MDK-ARM 的模式,不然就变成了 Keil 了。然后生成,也就是 generate code,生成好后,会出现 Core 和 Drivers的文件夹以及其他的一些文件。

回到 CLion,他会要你选择一个 cfg,这里的 cfg,我看网上说的,各个都说的轻飘飘的。我也看的云里雾里,不清楚。反正他们的意思是这个文件并不太重要。然而事实也确实是如此。我们只需要关注文件里的两个,一个是 Interface 下的调试器。像我用的是 stlink,所以里面的就是 source [find interface/stlink.cfg],不得不说,stlink 这个调试器是真的无脑,而且下载速度快。除此之外还有一个 target 里面的文件,叫你选择一个单片机处理器相关的文件。直接看型号就行。像我用的探索者板子,芯片是 stm32f407ZGT6,所以这里的配置就是source [find target/stm32f4x.cfg]

当然上面这么多,都不是自己配的,我就是直接在回到 CLion 的界面中选择了 stm32f4discovery.cfg 的选项就可以了。里面就已经有这两行给你配好了。也就是说不用自己再去配了。

这里最神奇,也就是说,从开始创建工程到现在,没有自己额外再去配的部分了,都是直接选择。到了这里,那个编译选项,工具链那个地方(就是 CLion 右上角的图标)自然而然就有了一个锤子样的符号(Build)和 OpenOCD 的一个 configuration ,并且 run 和 debug 都是亮着的,说明是可以直接点击开始跑的。这时候你再点开 Edit configuration ,你就能看到里面已经给你配好了,也就是说,这里好像和你之前的那个配置工具链没有什么关系。所以这里我自己也不太清晰,但是程序能跑就行。

这里你再点击编译,点击下载,就能成功下载了。至此,我们也就云里雾里的成功配置好,并且程序能跑了。

工程移植

工程移植还是比较麻烦的。直接复制粘贴会出现我的配置文件选用的是原来文件夹里的。然后经过一番倒腾,我发现了一个能行的通的方法。

首先不能直接复制工程,不然后面会很混乱,到底哪个是哪个工程的配置。我们这里应该要新建一个工程,自己取名字等等。

然后新建完一个工程后他会叫你打开并编辑 .ioc 文件,这里就不急,直接把他生成的这个给删掉,然后从原来的工程里把那个复制过来,注意,建议把这个 .ioc 文件名字改成现在工程的名字。不然又乱了。。。。

注意这里很重要,现在要直接用这个文件生成代码,不能直接把代码从原来的工程搬过来。一定要自己这边先生成空的模板代码。

生成完模板代码后,再把原来工程中带有我们的编写信息的代码文件,比如 main.c,maic.h以及其他我们自己的写的头文件和源文件。仅仅把这些我们自己写的文件移植过来。

这时候我们还需要取重新加载这个 CMake 工程。右键 CLion 中的工程文件夹就有这个选项了。

这时候,进行编译,并且进行下载,就能正常下载程序了。

大功告成!

Hexo 框架

我的这个 Hexo 是托管在 Github 上,这个特点我也已经在 about 中说过了。速度还是奇慢无比,但我还是决定不换了。阻力太大,动力太小。哈哈。

记住这么几个文件,_config.yml 和 source/_data/styles.styl。

目录导航问题

目录导航我之前忘了是在哪里配置的了。但这个不重要,很简单。但是有个让我很恼火的就是这个侧边目录无法进行导航。打开 F12 的开发者界面显示报错。我也看不懂。在 Github 上看到这个 Issue,但是上面提供的解决方法是将一个 js 文件进行改动。但是改动后的正确的 js 脚本,就是我这个。所以我就迷惑了。

后来在这个大佬的博客里找到,这个大佬也是用 Hexo 的,看来也是踩过许多坑。这个解决方法是将 node_modules\hexo-toc\lib\filter.js 中的第29到31行注释,而将原本被注释的28行取消注释。然后重新部署博客,立竿见影,马上就能进行侧边的目录导航。欢喜!

1
2
3
4
$title.attr('id', id);
// $title.children('a').remove();
// $title.html( '<span id="' + id + '">' + $title.html() + '</span>' );
// $title.removeAttr('id');

背景图片浮动问题

我设置了背景图片浮动,也就是说背景图片只占用一页,使用滚轮下滑背景图片会跟着被划上去,但是现在表现为有些地方是这种效果,比如我电脑上的 Microsoft Edge 和 Google Chrome 都可以。但我室友的电脑上的QQ Browser 和 华为浏览器就不行。即背景图被固定住,不会随着页眉滑动。以及移动端进行查看时也会出现固定的情况。

于是我的解决方案是,干脆就将背景图片设置成固定的好了。现在无论哪里都是统一的固定住的模样了。耶比耶比~

Next 主题

我还是用了 Next 主题。显然我也不想换。主题换起来会让我觉得阻力巨大。srds,我还是很憧憬 butterfly 主题的。Next 主题有个不好的地方是主页不能够放一些图片,颜色也单调,显得这个博客过于的拘谨严肃了。而 butterfly 就挺好了。

Next 下的文件主要是 themes/next/_config.yml。

边框、阴影

此处省略许多字。。。

Altium Designer 概述

AD 这个软件很不错。。。。

封装技巧

画封装可以多个component在一个schLib中,同样pcbLib 中也可以有多个

原理图技巧

PCB 技巧

铺铜

铺铜中的技巧在于重新铺铜和抠铜

重新铺铜只需选中铜区然后分别按下T + G + R,三个键,一定要英文模式下(AD所有快捷键都是在英文模式下)

扣除不必要的铜但又要通过 DRC 可以先画一个矩形,画完后直接按下T + V + T ,即选中Create Cutout from selected primitives,产生铺铜的一个边界,然后在删除矩形重新铺铜即可。会在原来矩形的地方留下一个虚线框。

图层

有 Mechanical 层和 Keep-Out 层。一个表示机械物理的边界,一个表示 PCB 上电气的边界。还有 Top Overlay 层,即丝印层。Top Solder 层 (阻焊层)

SSH 概述

ssh 本质是 Secure Shell ,ssh协议安全,可靠,有效。现在使用量大,普遍。比如我就在用。

SSH 为 [Secure Shell](https://baike.baidu.com/item/Secure Shell) 的缩写,由 IETF 的网络小组(Network Working Group)所制定;SSH 为建立在应用层基础上的安全协议。SSH 是较可靠,专为远程登录会话和其他网络服务提供安全性的协议。利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。SSH最初是UNIX系统上的一个程序,后来又迅速扩展到其他操作平台。SSH在正确使用时可弥补网络中的漏洞。SSH客户端适用于多种平台。几乎所有UNIX平台—包括HP-UXLinuxAIXSolaris、Digital UNIXIrix,以及其他平台,都可运行SSH。

以上来自百度百科 (严谨)

关于 SSH 的使用还是相对比较麻烦的。还是一样的总是忘,忘了查,查了记,记了忘。并且每次都会回到最开始的理解,即我后来即使有了自己的一定理解过后,还是会忘。。。。

SSH 的一些配置记录和方法

目录

SSH 在操作系统中的目录形式都表现为有一个 ~/.ssh 的目录。Linux 下目录即为使用者家目录下,Windows 中则为 C:\Users\你的用户名 这个目录下。在这个.ssh 目录中会有一些必要的配置文件之类的一些东西存储在其中。且操作系统有关 SSH 的任何操作和记录都在其中,与其他无关。

文件

.ssh 目录下的文件主要是这些(至少我的操作系统上用到并产生的文件是这些)

  1. config
  2. id_rsa.pub/id_rsa
  3. know_hosts/know_hosts.old
  4. authorized_keys

其中 config 是一些配置,是关于多个 ssh 目标时使用 config 来进行区分。 id_rsa 是本机的私有密钥,pub 后缀则是公钥。传输认证时服务器事先存储主机(客户机)的公钥,然后主机传输私钥进行请求,服务器根据存储的公钥进行识别。authorized_keys 作用于服务器,识别标记主机,使得主机在每次请求连接时都不用再输入密码。

其中 id_rsa 可以用 genkey 命令生成。我在Linux中在配置Git时使用了这个,但是锁定的是我的 Git 邮箱账户,而非我的 Linux 系统主机。当时使用的命令为

1
ssh-keygen -t rsa -C "[email protected]"

使用的便是我的邮箱,后来我又使用了ssh-keygen 直接生成了主机名字的 id_rsa.pub/id_rsa 的密钥对。

config

config 的具体配置如下。一般情况下要将 git 的 User 设置为 git 或者干脆不设置,才可以正常运行,我试过将 User 改为我的 github,gitee 帐号对应的用户后无法正常工作。貌似也确实是这样,估计是我的用户名其实相当于是github下的一个路径而已。因为就github和gitee的提示而言,他们都是[email protected]/username/project.git 的路径。所以类比于 User@HostName ,这里也应该是填写 git。目前还是一种自己的猜测。

如果连这个 config 都不进行设置的话,在使用 ssh 的时候将会出现permission denied (Publickey) 的报错。

1
2
3
4
5
6
7
8
9
10
11
Host github.com
HostName github.com
User git
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa

Host gitee.com
HostName gitee.com
User git
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa_gitee

可以使用ssh -vT github.com/gitee.com 或者ssh github.com/gitee.com 来进行验证。以下是直接使用ssh进行测试连接的。其中的第一行PTY allocation request failed on channel 0暂时还不清楚。有待后续研究试错。

1
2
3
4
5
6
7
8
$> ssh [email protected]
PTY allocation request failed on channel 0
Hi xxx(你的用户名)! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.
$> ssh github.com
PTY allocation request failed on channel 0
Hi xxx(你的用户名)! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.

其中具体参数的讲解可以看看库这个某乎的链接

其中上面的Host 类似于是一个别名,Host 相当于是 User@HostName。例如这里面 Host 的gitee.com 就相当于是 [email protected] 。假如是一个远程主机的话就可以写用户名@主机名了。比如我的虚拟机的用户名,和我虚拟机的主机名,填写上去是可以正常运行的。