cake脚本本质是c#代码,由cake.exe编译执行;任务须用task("name")声明,依赖通过isdependenton()显式定义,推荐使用dotnet()而非已废弃的dotnetcorecli()。

Cake脚本本质是C#,不是“C# Make”
Cake(C# Make)不是另一个构建工具,而是用C#写的构建脚本框架——Cake.exe 本身是.NET命令行宿主,它把你的 build.cake 当作C#代码编译执行。所谓“用C#定义任务”,就是直接写C#语法,调用Cake提供的DSL方法(比如 Task()、DotNetBuild()),而不是去学一套新语言。
常见错误现象:CS0103: The name 'Task' does not exist in the current context —— 这通常是因为没加 #load "tools/Cake.Cake" 或没启用预处理器指令,或者用错了入口点(比如写了 public static void Main(),但Cake不走这个)。
- 所有任务必须用
Task("name")声明,不能用void Build()这类普通方法代替 -
build.cake文件顶部要加#tool "nuget:?package=Cake.DotNetTool&version=3.2.0"(如果用dotnet tool方式运行)或#addin "Cake.Common"(传统packages.config方式) - 别在脚本里写
using static Cake.Common.Tools.DotNet.DotNetAliases—— Cake会自动注入常用别名,手动using反而可能冲突
Task() 的参数和执行顺序怎么控制
Cake的任务调度是显式依赖的,没有隐式“默认任务”或“按顺序执行”。Task() 返回的是 ICakeTaskBuilder,靠 .IsDependentOn()、.IsScheduled() 和 .Does() 组装逻辑。
使用场景:你想先 restore 再 build 再 test,但又不想把三件事塞进一个 Does() 里——这样不利于复用和调试。
- 基础写法:
Task("Build").IsDependentOn("Restore").Does(() => { DotNetBuild(...); }); - 避免循环依赖:
Task("A").IsDependentOn("B"); Task("B").IsDependentOn("A");运行时会直接报Cake.Core.CakeException: Circular dependency detected - 条件跳过用
.WithCriteria(),比如.WithCriteria(() => !BuildSystem.IsLocalBuild),比在Does()里写if更干净 - 别在
Does()里 throw 异常来“失败任务”——用throw new InvalidOperationException()是可以的,但更推荐Error("message"),它会标记任务失败且不影响后续可选任务
DotNetCoreCLI vs DotNetTool:该用哪个命令封装
DotNetCoreCLI() 是旧版API(已标记为 obsolete),DotNet() 才是当前推荐的统一入口。二者参数结构不同,混用容易传错参数类型(比如 DotNetCoreBuildSettings 和 DotNetBuildSettings 不兼容)。
性能影响:用 DotNet() 调用 dotnet build 时,Cake会复用已启动的MSBuild节点(如果环境支持),而老接口可能每次新建进程。
- 正确写法:
DotNetBuild("./src/MyApp.sln", new DotNetBuildSettings { Configuration = "Release" }); - 路径必须是相对
build.cake的位置,不是当前工作目录——"./src/MyApp.sln"可以,"src/MyApp.sln"在某些平台会失败 - 如果项目用了
<packagereference></packagereference>方式引用Cake.Common,确保tools/目录下没有残留的packages.config,否则DotNet()可能加载不到扩展
本地调试 build.cake 很麻烦?试试直接用 dotnet run
Cake脚本不能双击运行,也不能用VS“启动调试”直接跑——因为缺少宿主上下文。最简单有效的调试方式,是把它当普通C#项目看待:用 dotnet run 加上 --project 指向一个临时的 .csproj,再通过 ProcessArgumentBuilder 模拟命令行参数。
容易踩的坑:很多人试图在 build.cake 里加 #r "System.Diagnostics.Debug.dll" 然后 Debugger.Launch(),结果发现根本不会弹窗——Cake进程由 Cake.exe 启动,调试器无法附着。
- 推荐做法:建一个
build-runner.csproj,PackageReference引入Cake.Frosting,写个Program.cs调用new CakeHost().UseContext<buildcontext>().Run(args)</buildcontext> - 或者更轻量:用
dotnet cake build.cake --verbosity=diagnostic,日志里能看到每一步的输入参数和环境变量 - 别在
Does()里写Console.WriteLine()查变量——用Information("Value: {0}", value),它会受--verbosity控制,不会污染CI输出
真正卡住人的地方,往往不是语法,而是 Cake 的生命周期:脚本解析 → 任务注册 → 依赖拓扑排序 → 执行链触发。一旦某个 Task() 注册失败(比如名字重复、依赖不存在),整个流程就停在解析阶段,连第一行 Information() 都不会输出。










