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()都不会输出。
