236 lines
7.7 KiB
Markdown
236 lines
7.7 KiB
Markdown
# 构建与部署
|
||
|
||
> 所属项目: free-code .NET 10 重写
|
||
> 文档类型: 构建设计
|
||
> 来源章节: DESIGN-NET10-PART3.md § 23
|
||
> 上级文档: [测试与构建总览](测试与构建.md)
|
||
|
||
---
|
||
|
||
## 概述
|
||
|
||
构建目标是跨 5 个平台的 AOT 原生二进制,输出单文件、无运行时依赖的可执行文件。MSBuild 通过 `Directory.Build.props` 统一管理全局属性,`build.sh` 封装多平台批量发布,`install.sh` 提供一键下载安装体验。
|
||
|
||
原始 TypeScript 项目使用 Bun 打包为单一 JavaScript bundle。.NET 重写的 AOT 路径在启动时间和内存占用上接近原生,同时消除了 Bun 运行时依赖。
|
||
|
||
---
|
||
|
||
## 23.1 MSBuild 配置
|
||
|
||
### Directory.Build.props(全局属性)
|
||
|
||
所有子项目自动继承这些属性,无需在每个 `.csproj` 中重复声明。
|
||
|
||
```xml
|
||
<!-- Directory.Build.props -->
|
||
<Project>
|
||
<PropertyGroup>
|
||
<TargetFramework>net10.0</TargetFramework>
|
||
<LangVersion>13.0</LangVersion>
|
||
<Nullable>enable</Nullable>
|
||
<ImplicitUsings>enable</ImplicitUsings>
|
||
<AotPublish>true</AotPublish>
|
||
<PublishSingleFile>true</PublishSingleFile>
|
||
<PublishTrimmed>true</PublishTrimmed>
|
||
<TrimMode>partial</TrimMode>
|
||
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
|
||
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
|
||
<EnableAotAnalyzer>true</EnableAotAnalyzer>
|
||
<Version>1.0.0</Version>
|
||
<AssemblyName>free-code</AssemblyName>
|
||
<RootNamespace>FreeCode</RootNamespace>
|
||
</PropertyGroup>
|
||
</Project>
|
||
```
|
||
|
||
关键属性说明:
|
||
|
||
| 属性 | 值 | 作用 |
|
||
|------|----|------|
|
||
| `AotPublish` | `true` | 启用 AOT 原生编译 |
|
||
| `PublishSingleFile` | `true` | 输出单一可执行文件 |
|
||
| `PublishTrimmed` | `true` | 裁剪未使用的程序集 |
|
||
| `TrimMode` | `partial` | 部分裁剪,保留反射入口点 |
|
||
| `JsonSerializerIsReflectionEnabledByDefault` | `false` | 强制使用 Source Generator 序列化 |
|
||
| `EnableAotAnalyzer` | `true` | 编译期检测 AOT 不兼容代码 |
|
||
| `LangVersion` | `13.0` | C# 13 特性(primary constructors、集合表达式等)|
|
||
|
||
---
|
||
|
||
### FreeCode.csproj(主项目)
|
||
|
||
```xml
|
||
<!-- FreeCode.csproj (主项目) -->
|
||
<Project Sdk="Microsoft.NET.Sdk">
|
||
<PropertyGroup>
|
||
<OutputType>Exe</OutputType>
|
||
<TargetFramework>net10.0</TargetFramework>
|
||
</PropertyGroup>
|
||
<ItemGroup>
|
||
<ProjectReference Include="..\FreeCode.Core\FreeCode.Core.csproj" />
|
||
<ProjectReference Include="..\FreeCode.Engine\FreeCode.Engine.csproj" />
|
||
<ProjectReference Include="..\FreeCode.Tools\FreeCode.Tools.csproj" />
|
||
<ProjectReference Include="..\FreeCode.Commands\FreeCode.Commands.csproj" />
|
||
<ProjectReference Include="..\FreeCode.ApiProviders\FreeCode.ApiProviders.csproj" />
|
||
<ProjectReference Include="..\FreeCode.Mcp\FreeCode.Mcp.csproj" />
|
||
<ProjectReference Include="..\FreeCode.Lsp\FreeCode.Lsp.csproj" />
|
||
<ProjectReference Include="..\FreeCode.Bridge\FreeCode.Bridge.csproj" />
|
||
<ProjectReference Include="..\FreeCode.Services\FreeCode.Services.csproj" />
|
||
<ProjectReference Include="..\FreeCode.Tasks\FreeCode.Tasks.csproj" />
|
||
<ProjectReference Include="..\FreeCode.Skills\FreeCode.Skills.csproj" />
|
||
<ProjectReference Include="..\FreeCode.Plugins\FreeCode.Plugins.csproj" />
|
||
<ProjectReference Include="..\FreeCode.Features\FreeCode.Features.csproj" />
|
||
<ProjectReference Include="..\FreeCode.State\FreeCode.State.csproj" />
|
||
<ProjectReference Include="..\FreeCode.TerminalUI\FreeCode.TerminalUI.csproj" />
|
||
</ItemGroup>
|
||
</Project>
|
||
```
|
||
|
||
主项目引用全部 15 个子项目,自身仅包含 `Program.cs` 入口,所有业务逻辑分布在各子项目库中。
|
||
|
||
---
|
||
|
||
## 23.2 构建脚本
|
||
|
||
### build.sh(多平台批量构建)
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# build.sh — 多平台构建
|
||
set -euo pipefail
|
||
|
||
VERSION="${1:-$(git describe --tags --always)}"
|
||
OUTPUT_DIR="./dist"
|
||
|
||
# 构建目标平台
|
||
PLATFORMS=(
|
||
"osx-arm64"
|
||
"osx-x64"
|
||
"linux-x64"
|
||
"linux-arm64"
|
||
"win-x64"
|
||
)
|
||
|
||
for PLATFORM in "${PLATFORMS[@]}"; do
|
||
echo "Building for $PLATFORM..."
|
||
RID="${PLATFORM}"
|
||
|
||
dotnet publish src/FreeCode/FreeCode.csproj \
|
||
-c Release \
|
||
-r "$RID" \
|
||
-o "$OUTPUT_DIR/$PLATFORM" \
|
||
/p:VersionPrefix="$VERSION" \
|
||
/p:AotPublish=true \
|
||
/p:PublishSingleFile=true \
|
||
/p:PublishTrimmed=true
|
||
|
||
# 重命名二进制
|
||
if [[ "$PLATFORM" == win-* ]]; then
|
||
mv "$OUTPUT_DIR/$PLATFORM/free-code.exe" \
|
||
"$OUTPUT_DIR/$PLATFORM/free-code-$VERSION-$PLATFORM.exe"
|
||
else
|
||
chmod +x "$OUTPUT_DIR/$PLATFORM/free-code"
|
||
mv "$OUTPUT_DIR/$PLATFORM/free-code" \
|
||
"$OUTPUT_DIR/$PLATFORM/free-code-$VERSION-$PLATFORM"
|
||
fi
|
||
|
||
echo "✓ $PLATFORM done"
|
||
done
|
||
|
||
echo "All builds complete in $OUTPUT_DIR/"
|
||
```
|
||
|
||
脚本逻辑说明:
|
||
|
||
1. 版本号优先读取命令行参数,fallback 到 `git describe --tags --always`
|
||
2. 遍历 5 个 RID,每个平台独立调用 `dotnet publish`
|
||
3. 输出产物按 `free-code-{VERSION}-{PLATFORM}` 格式命名
|
||
4. Windows 平台保留 `.exe` 后缀,其余平台添加可执行权限
|
||
|
||
---
|
||
|
||
## 23.3 安装脚本
|
||
|
||
### install.sh(一键安装)
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# install.sh — 一键安装
|
||
set -euo pipefail
|
||
|
||
# 检测平台
|
||
OS="$(uname -s)"
|
||
ARCH="$(uname -m)"
|
||
|
||
case "$OS-$ARCH" in
|
||
Darwin-arm64) PLATFORM="osx-arm64" ;;
|
||
Darwin-x86_64) PLATFORM="osx-x64" ;;
|
||
Linux-x86_64) PLATFORM="linux-x64" ;;
|
||
Linux-aarch64) PLATFORM="linux-arm64" ;;
|
||
*) echo "Unsupported platform: $OS-$ARCH"; exit 1 ;;
|
||
esac
|
||
|
||
INSTALL_DIR="$HOME/.free-code/bin"
|
||
mkdir -p "$INSTALL_DIR"
|
||
|
||
# 下载
|
||
BINARY_URL="https://github.com/paoloanzn/free-code/releases/latest/download/free-code-latest-$PLATFORM"
|
||
echo "Downloading free-code for $PLATFORM..."
|
||
curl -fsSL "$BINARY_URL" -o "$INSTALL_DIR/free-code"
|
||
chmod +x "$INSTALL_DIR/free-code"
|
||
|
||
# 添加到 PATH
|
||
if ! echo "$PATH" | grep -q "$INSTALL_DIR"; then
|
||
SHELL_RC="$HOME/.zshrc"
|
||
[ -f "$HOME/.bashrc" ] && SHELL_RC="$HOME/.bashrc"
|
||
echo "export PATH=\"$INSTALL_DIR:\$PATH\"" >> "$SHELL_RC"
|
||
echo "Added $INSTALL_DIR to PATH in $SHELL_RC"
|
||
fi
|
||
|
||
echo "✓ free-code installed to $INSTALL_DIR/free-code"
|
||
echo " Run 'free-code' to start"
|
||
```
|
||
|
||
安装流程:
|
||
|
||
1. 通过 `uname -s` 和 `uname -m` 检测当前平台
|
||
2. 从 GitHub Releases 下载对应 RID 的预编译二进制
|
||
3. 安装到 `~/.free-code/bin/free-code`
|
||
4. 自动检测 shell 配置文件(优先 `.zshrc`,fallback `.bashrc`)并追加 PATH
|
||
|
||
---
|
||
|
||
## 23.4 目标平台矩阵
|
||
|
||
| RID | 操作系统 | 架构 | 说明 |
|
||
|-----|---------|------|------|
|
||
| `osx-arm64` | macOS | Apple Silicon | M1/M2/M3 Mac |
|
||
| `osx-x64` | macOS | Intel x64 | Intel Mac |
|
||
| `linux-x64` | Linux | x86-64 | 主流 Linux 服务器 |
|
||
| `linux-arm64` | Linux | AArch64 | Raspberry Pi、AWS Graviton 等 |
|
||
| `win-x64` | Windows | x64 | Windows 10/11 |
|
||
|
||
---
|
||
|
||
## 23.5 发布参数说明
|
||
|
||
| dotnet publish 参数 | 含义 |
|
||
|---------------------|------|
|
||
| `-c Release` | Release 配置,开启优化 |
|
||
| `-r {RID}` | 目标运行时,指定后产物为自包含 |
|
||
| `/p:AotPublish=true` | AOT 原生编译,消除 JIT 开销 |
|
||
| `/p:PublishSingleFile=true` | 将所有资源打包为单一可执行文件 |
|
||
| `/p:PublishTrimmed=true` | 裁剪未引用的程序集,减小体积 |
|
||
| `/p:VersionPrefix={VERSION}` | 注入版本号到程序集元数据 |
|
||
|
||
AOT 编译将 IL 代码提前编译为目标平台原生机器码,启动时间从 JIT 模式的数百毫秒降至个位数毫秒,与原始 Bun 构建产物的冷启动时间相当。
|
||
|
||
---
|
||
|
||
## 参考资料
|
||
|
||
- [测试与构建总览](测试与构建.md)
|
||
- [原始代码映射 — 测试与构建](reference/原始代码映射-测试与构建.md)
|
||
- [总体概述与技术选型](../总体概述与技术选型/总体概述与技术选型.md)
|
||
- [迁移路线图](测试与构建-迁移路线图.md)
|