MDCS仓库布局与构建链
概述 / Overview
MDCS 由 7 个并列仓库组成;按依赖关系自底向上构建。本页详述各仓库职责、产物、构建顺序、引用程序集机制。
MDCS consists of 7 sibling repositories built bottom-up by dependency. This page details responsibilities, outputs, build order, and the reference-assembly mechanism.
仓库一览 / Repositories
| 仓库 / Repo | 解决方案 / Solution | 产物 / Output | 角色 / Role |
|---|---|---|---|
| `D:\src\Fundamentals\` | Fundamentals.sln | FundamentalLib.dll, FundamentalLib2.dll, LessokajiProtect.dll, LessokajiLicencer.dll | 通用类型 + IPC + 日志 + 许可 |
| `D:\src\LessokajiWeaver\` | LessokajiWeaver.sln | LessokajiWeaver.Fody.dll, LessokajiWeaverUtilities.dll | 编译期 IL 注入(Fody) |
| `D:\src\CycleGUI\` | CycleGUI.sln | CycleGUI.dll, libVRender.dll(C++/Vulkan), webVRender(WASM) | 懒协程 UI 框架 |
| `D:\src\M2\` | M2.sln | MedullaCore.dll, OfficialPlugins/*.dll | 硬件抽象内核 + 一方插件(雷达 / 相机 / Cart) |
| `D:\src\Detour\` | Detour.sln | Detour.exe(.NET 4.8 GUI),DetourLite.exe(.NET 8 headless),DetourCore.dll | 定位系统 |
| `D:\src\Clumsy\` | Clumsy.sln | ClumsyCore.dll, ClumsyDance.dll | 车载自动驾驶 |
| `D:\src\Simple\` | Simple.sln | SimpleCore.dll, SimpleComposer.exe(Nancy HTTP) | 车队管理 |
依赖图 / Dependency graph
Fundamentals ◄────────── (everything)
▲
│
CycleGUI ◄─ Detour ─── (M2, Clumsy, Simple use indirectly)
▲ ▲
│ │
M2 ◄────── Clumsy ◄── Simple
▲
└─── LessokajiWeaver (build-time only)
构建顺序 / Build order
自底向上 / Bottom-up:
- LessokajiWeaver — 构建时依赖(Fody 织入)
- Fundamentals — 用 Weaver
- CycleGUI — 用 Fundamentals;需 libVRender C++ 先构建
- M2 / MedullaCore — 用 Fundamentals + CycleGUI
- M2 / OfficialPlugins/\* — 用 MedullaCore
- Detour / DetourCore — 用 Fundamentals + CycleGUI
- Clumsy / ClumsyCore → ClumsyDance
- Simple / SimpleCore → SimpleComposer
每个仓库独立 .sln;可单独 `dotnet build` / 在 IDE 打开。 Each repo has its own .sln; independently buildable.
引用程序集机制 / Reference-assembly mechanism
概念 / Concept
每个核心 DLL 同时产生一个 仅引用的程序集 `Ref<Name>.dll`,通过 [refasmer] 工具生成。
Each core DLL also emits a reference-only assembly (`Ref<Name>.dll`) via refasmer.
例如 `MedullaCore.dll` → `RefMedullaCore.dll`:后者只含 public/protected API 签名,没有方法体。 E.g. `MedullaCore.dll` → `RefMedullaCore.dll`: signature-only.
为什么 / Why
插件 csproj 引用 `Ref<Name>.dll`,不引用 impl DLL : Plugin csproj references the `Ref` assembly:
- 插件构建不会拉入 Costura 织入的传递依赖(FodyWeavers.xml + LessokajiWeaver 等)。
- 公共 API 由 Ref assembly 固定 —— `internal` 成员对插件不可见,强制良好的封装。
- 插件 DLL 体积小、加载快。
- No Costura transitives pulled into plugin builds.
- Public API frozen by the Ref assembly; `internal` hidden from plugins — enforced encapsulation.
- Smaller plugin DLLs, faster load.
生成 / Generation
每个核心 csproj 有 AfterBuild 目标调 refasmer,输出到 `<repo>/tools/Ref<Name>.dll`:
<Target Name="GenerateRefAssembly" AfterTargets="Build">
<Exec Command="refasmer $(TargetPath) -o $(SolutionDir)tools\Ref$(AssemblyName).dll" />
</Target>
详见 `D:\src\M2\OfficialPlugins\CartActivator\CartActivator.csproj:47-54`。
更新流程 / Update flow
改动 `MedullaCore` 公共面 → 重新 build → 同时 rebuild Ref assembly → 把 两个 DLL(impl + ref)都提交到仓库。
Change `MedullaCore` public surface → build → rebuild Ref → commit both.
【注意】 插件 csproj 用旧 `Ref` 构建 不会出错,但运行时调新成员会 `MissingMethodException`。
A plugin built against the old Ref doesn't fail to compile but throws `MissingMethodException` at runtime when calling the new member.
`tools/` 目录约定 / `tools/` directory convention
每个仓库根有 `tools/` 子目录,存放 其它仓库的 Ref assembly + 二进制工具(refasmer.exe 等)。插件 csproj 通过相对 HintPath 引用 :
Each repo root has a `tools/` subdirectory containing reference assemblies from other repos + binary tools (refasmer.exe). Plugin csproj uses relative HintPaths:
<Reference Include="RefFundamentalLib">
<HintPath>..\tools\RefFundamentalLib.dll</HintPath>
</Reference>
【发现】 `..\tools\` 是 仓库一致约定 —— 每个 MDCS 插件 csproj 都这么写。不要改成 NuGet 包;现有工具链不支持。 The `..\tools\` HintPath pattern is repo-wide. Don't try to NuGet-ify it.
Costura.Fody 胖 DLL 打包 / Fat DLL packaging
插件 / 客户端 exe 用 Costura.Fody把所有依赖打到一个 DLL 的 base64 资源里。最终客户只需要 1 个文件。 Plugins / client exes use Costura.Fody to embed all deps as base64 resources in one DLL. Customer deploys one file.
注意 :
- 核心 DLL(MedullaCore, ClumsyCore, ...)不用 Costura。它们要被多个插件 共载,loose DLL 必要。
- 插件 / 顶层 exe 用 Costura。简化部署。
Note: Core DLLs (MedullaCore, ClumsyCore, ...) must not use Costura — they need to be shared between plugins. Plugins / top-level exes use Costura for deployment simplicity.
LessokajiWeaver 编译期注入 / Compile-time IL injection
Fody 加上 `LessokajiWeaver.Fody.dll` 在编译后做 IL 重写。当前生效的规则 : Fody + `LessokajiWeaver.Fody.dll` rewrites IL post-compile. Active rules:
- `[AsInitParam] / [AsUpperIO] / [AsLowerIO]` 字段 → 自动同步 DObject 的 property
- `[ReplaceWithCompileInfo]` 字段 → 编译时戳 + git 哈希
- `[Translatable] / [T(zh=, en=)]` 字段 → getter 按 `CultureInfo.CurrentUICulture` 分派
详见 LessokajiWeaver编译后处理工具 与 如何使用LessokajiWeaver的多语言功能。
跨平台 / Cross-platform
- 多数仓库 .NET 6/8,部分 .NET Framework 4.8(旧 lidar driver / Detour.exe)。
- Linux 支持 :Medulla, Detour (Lite), Clumsy, SimpleComposer 都可跑。
- CycleGUI 的 libVRender 在 Linux 上有 build;Windows 是主战场。
仓库间集成测试 / Cross-repo integration
没有单一 mega-solution。集成测试靠: There's no monolithic solution. Integration tests rely on:
- 改动核心后重 build 所有受影响插件。
- 在仿真车 SimpleComposer 里跑完整任务序列。
- `D:\src\Fundamentals\Test\` 单元测试(DObject + DLog 等关键基础)。
仓库镜像 / Repo mirror
- 内部 git:`git.lessokaji.com`(私有)。
- 下载站:`dl.lessokaji.com`(编译产物)。
- 认证 / 许可:`auth.lessokaji.com`。